home *** CD-ROM | disk | FTP | other *** search
/ Aminet 50 / Aminet 50 (2002)(GTI - Schatztruhe)[!][Aug 2002].iso / Aminet / text / edit / tecoc-146.lha / zvms.c < prev   
C/C++ Source or Header  |  1991-07-11  |  70KB  |  2,281 lines

  1. /*****************************************************************************
  2.     Zvms.c
  3.     System dependent code for VAX/VMS.
  4. *****************************************************************************/
  5.  
  6. #include <stdio.h>
  7. #include <stdlib.h>        /* EXIT_SUCCESS and EXIT_FAILURE */
  8. #include <string.h>        /* prototype for strlen */
  9.  
  10. #include dcdef            /* device class identifiers */
  11. #include descrip        /* string descriptor macros */
  12. #include dvidef            /* dvi item identifier codes */
  13. #include fab            /* RMS file access block structures */
  14. #include hlpdef            /* HLP$... identifiers */
  15. #include iodef            /* i/o code identifiers */
  16. #include jpidef            /* JPI$_... identifiers */
  17. #include libclidef        /* LIB$K_CLI_LOCAL_SYM */
  18. #include lib$routines        /* lib$ routines */
  19. #include rab            /* RMS record access block structures */
  20. #include rmsdef            /* RMS return status identifiers */
  21. #include signal            /* arguments to function signal() */
  22. #include ssdef            /* SS$_NORMAL and SS$_BADESCAPE */
  23. #include stsdef            /* $VMS_STATUS_SUCCESS macro */
  24. #include starlet        /* sys$ routines */
  25. #include ttdef            /* ttdef union */
  26. #include tt2def            /* tt2def union */
  27.  
  28. #include "zport.h"        /* portability identifiers */
  29. #include "tecoc.h"        /* general identifiers */
  30. #include "chmacs.h"        /* character processing macros */
  31. #include "clpars.h"        /* command-line parsing macro */
  32. #include "dchars.h"        /* identifiers for characters */
  33. #include "deferr.h"        /* identifiers for error messages */
  34. #include "defext.h"        /* external global variables */
  35. #include "dscren.h"        /* identifiers for screen i/o */
  36.  
  37. #define SOBSIZE        1024
  38. #define TERM_IN_EFN    1    /* terminal input event flag */
  39. #define TERM_OUT_EFN    2    /* terminal output event flag */
  40.  
  41. struct getxxx_iosb_struct {        /* for calling $getdvi or $getjpi */
  42.     unsigned int io_status;
  43.     unsigned int reserved_to_Digital;
  44. };
  45. struct tt_mode_iosb_struct {        /* for setting/sensing term. modes */
  46.     unsigned short io_status;
  47.     unsigned char transmit_speed;
  48.     unsigned char receive_speed;
  49.     unsigned char CR_fill_count;
  50.     unsigned char LF_fill_count;
  51.     unsigned char parity_flags;
  52.     unsigned char unused;
  53. };
  54. struct tt_rw_iosb_struct {        /* for reading/writing to terminal */
  55.     unsigned short io_status;
  56.     unsigned short byte_count;
  57.     unsigned short terminator;
  58.     unsigned short terminator_size;
  59. };
  60. struct tt_mode_characteristics_struct {
  61.     unsigned char class;        /* device class */
  62.     unsigned char type;        /* terminal type */
  63.     unsigned short nbr_columns;    /* number of columns */
  64.     union ttdef lw2;        /* longword 2 */
  65. };
  66.  
  67.  
  68. static    struct    FAB IFab;        /* input file access block */
  69. static    struct    NAM INam;        /* input name block */
  70. static    struct    RAB IRab;        /* input file record access block */
  71. static    struct    FAB OFab;        /* output file access block */
  72. static    struct    NAM ONam;        /* output name block */
  73. static    struct    RAB ORab;        /* output file record access block */
  74. static    unsigned char *TIBBeg;        /* SYS$INPUT buffer */
  75. static    unsigned char *TIBEnd;        /* SYS$INPUT buffer end */
  76. static    unsigned char *TIBERc;        /* ptr to end of record in buffer */
  77. static    unsigned char *TIBPtr;        /* ptr to current char in record */
  78. static    unsigned char TOBBeg[SOBSIZE];    /* SYS$OUTPUT buffer */
  79. static    unsigned char *TOBEnd;        /* SYS$OUTPUT buffer end (+1) */
  80. static    unsigned char *TOBPtr;        /* SYS$OUTPUT buffer pointer */
  81. static    struct    FAB TIFab;        /* SYS$INPUT file access block */
  82. static    struct    RAB TIRab;        /* SYS$INPUT record access block */
  83. static    struct    FAB TOFab;        /* SYS$OUTPUT file access block */
  84. static    struct    RAB TORab;        /* SYS$OUTPUT record access block */
  85. static    short    TCChan = 0;        /* terminal command channel */
  86. static    short    TIChan = 0;        /* terminal input channel */
  87. static    short    TOChan = 0;        /* terminal output channel */
  88. static  struct    tt_mode_characteristics_struct tt_chars;
  89. static    char    WBfExp[NAM$C_MAXRSS];    /* wildcard expanded filename buf */
  90. static    struct    FAB WFab;        /* wildcard file access block */
  91. static    struct    NAM WNam;        /* wildcard name block */
  92.  
  93. /*****************************************************************************
  94.     IFiles holds the file data blocks for input files.  There are three
  95. static input streams:   the primary input stream,  the secondary input stream,
  96. and the input stream used by the EQq command.  To access these three files,
  97. identifiers defined in file tecoc.h are used to index into this array.
  98. Other elements of this array are used to access input files for the EI
  99. command.
  100. *****************************************************************************/
  101.  
  102. static struct IFile_struct {
  103.     struct    FAB    IFab;        /* file access block */
  104.     struct    NAM    INam;        /* NAM block */
  105.     struct    RAB    IRab;        /* record access block */
  106.     BOOLEAN leftover_input_exists;    /* after-FF text saved? (ZRdLin) */
  107.     char *leftover_input;        /* after-FF text (see ZRdLin) */
  108.     size_t leftover_size;        /* after-FF text size (see ZRdLin) */
  109. } IFiles[NIFDBS];
  110.  
  111. /*****************************************************************************
  112.     OFiles holds the file data blocks for the output files.  There are
  113. three output streams:   the primary output stream,  the secondary output
  114. stream and the output stream used by the E%q command.  The array is indexed
  115. using identifiers defined in file tecoc.h.
  116. *****************************************************************************/
  117.  
  118. static struct {
  119.     struct    FAB    OFab;        /* file access block */
  120.     struct    NAM    ONam;        /* NAM block */
  121.     struct    RAB    ORab;        /* record access block */
  122. } OFiles[NOFDBS];
  123.  
  124. /*****************************************************************************
  125.  
  126.     ZErMsg()
  127.  
  128.     This function displays error message from the operating system on
  129. the terminal screen.  The error message text is retrieved from the operating
  130. system and imbedded in a TECO-style message with the SYS mnemonic.
  131.  
  132. *****************************************************************************/
  133.  
  134. static int v_action(    struct dsc$descriptor_s *msg_desc,
  135.             struct dsc$descriptor_s *errstr_desc)
  136. {
  137.     MEMMOVE(    errstr_desc->dsc$a_pointer,    /* destination */
  138.             msg_desc->dsc$a_pointer,    /* source */
  139.             msg_desc->dsc$w_length);    /* size */
  140.     errstr_desc->dsc$w_length = msg_desc->dsc$w_length;
  141.     return SS$_ACCVIO;
  142. }
  143.  
  144. static VVOID ZErMsg(    /* display an operating-system-supplied message */
  145.     int stat1,
  146.     int stat2)
  147. {
  148.     struct
  149.         {
  150.         short    argcnt;        /* argument count */
  151.         short    msgflg;        /* message flags */
  152.         int    msgcod;        /* message code */
  153.         int    rmsstv;        /* RMS alternate status */
  154.         } msgvec;
  155.     unsigned int status;
  156.     charptr tptr;
  157.     struct    dsc$descriptor errstr_desc;
  158.     char errstr[132];
  159.  
  160.     errstr_desc.dsc$w_length  = sizeof(errstr) - 1;
  161.     errstr_desc.dsc$a_pointer = &errstr[1];
  162.  
  163.     msgvec.argcnt = 2;        /* number of longwords in msgvec */
  164.     msgvec.msgflg = 15;        /* display all parts of message */
  165.     msgvec.msgcod = stat1;        /* message code */
  166.     msgvec.rmsstv = stat2;        /* RMS alternate status */
  167.  
  168.     status = sys$putmsg(    &msgvec,    /* message vector */
  169.                 v_action,    /* action routine */
  170.                 0,        /* facility name */
  171.                 &errstr_desc);    /* errstr descriptor */
  172.  
  173.     if (!$VMS_STATUS_SUCCESS(status)) {
  174.         lib$stop(status);
  175.     }
  176.  
  177. /*
  178.  * If the message is a successful one,  then inform the user by surrounding
  179.  * the text in brackets.  That way the user won't think an actual error has
  180.  * occurred.  If it's not successful, just display it.
  181.  */
  182.  
  183.     if ($VMS_STATUS_SUCCESS(stat1)) {
  184.         errstr[0] = '[';
  185.         tptr = &errstr[errstr_desc.dsc$w_length];
  186.         tptr++;
  187.         *tptr++ = ']';
  188.         errstr[errstr_desc.dsc$w_length] = '\0';
  189.         TypBuf(errstr, tptr);
  190.     } else {
  191.         errstr[errstr_desc.dsc$w_length+1] = '\0';
  192.         ErrStr(ERR_SYS, &errstr[1]);
  193.     }
  194. }
  195.  
  196. /*****************************************************************************
  197.  
  198.     ZAlloc()
  199.  
  200.     This function allocates memory.  The single argument is the number of
  201. bytes to allocate.  TECO-C uses the ZFree and ZRaloc functions to de-allocate
  202. and re-allocate, respectively,  the memory allocated by this function.
  203.  
  204. *****************************************************************************/
  205.  
  206. voidptr ZAlloc(SIZE_T MemSize)        /* allocate memory */
  207. {
  208.     return malloc(MemSize);
  209. }
  210.  
  211. /*****************************************************************************
  212.  
  213.     ZBell()
  214.  
  215.     Thus function rings the terminal bell.  For most platforms,  this
  216. means just writing a bell character (control-G) to the terminal.  Under
  217. MS-DOS, ringing the bell this way produces a yucky sound,  so for MS-DOS
  218. this function controls the signal generator directly.
  219.  
  220. *****************************************************************************/
  221.  
  222. VVOID ZBell(void)
  223. {
  224.     ZDspCh('\7');
  225. }
  226.  
  227. /*****************************************************************************
  228.  
  229.     ZChIn()
  230.  
  231.     This function inputs a single character from the terminal.
  232.  
  233.     1.  the character is not echoed on the terminal
  234.     2.  ^C calls an interrupt routine.  Note that this must be
  235.         implemented so that a ^C will cancel a current output via
  236.         ZDspBf.  The ^C must be a true interrupt.
  237.     3.  type-ahead is always nice
  238.     4.  The character must be returned immediately:  no fooling
  239.         around waiting for a carriage-return before returning.
  240.     5.  If the NoWait argument is TRUE, don't wait
  241.     6.  When the user hits the RETURN key,  TECO is supposed to see
  242.         a carriage return and then a line feed.  The function must
  243.         deal with this by returning a carriage return to the caller
  244.         and then "remembering" to send a line feed on the next call.
  245.     7.  handle ET_BKSP_IS_DEL flag
  246.  
  247. *****************************************************************************/
  248.  
  249. DEFAULT ZChIn(BOOLEAN NoWait)    /* input a character from the terminal */
  250. {
  251.     unsigned char Charac;
  252.     int    io_function =    IO$_READVBLK|
  253.                 IO$M_NOFILTR|
  254.                 IO$M_NOECHO;
  255.     static    BOOLEAN    LastCR = FALSE;
  256.     unsigned int status;
  257.     struct    tt_rw_iosb_struct ttread_iosb;
  258.  
  259.     if (TIChan) {                /* if it's a terminal */
  260.         if (LastCR) {            /* if last char was a <CR> */
  261.             LastCR = FALSE;
  262.             return (DEFAULT)LINEFD;
  263.         }
  264.         if (NoWait) {
  265.             io_function |= IO$M_TIMED;
  266.         } else {
  267.             io_function &= ~IO$M_TIMED;
  268.         }
  269.         status = sys$qiow(
  270.                 TERM_IN_EFN,    /* event flag number */
  271.                 TIChan,        /* channel */
  272.                 io_function,    /* I/O function */
  273.                 &ttread_iosb,    /* I/O status block */
  274.                 0,        /* AST routine address */
  275.                 0,        /* AST parameter */
  276.                 &Charac,    /* input buffer */
  277.                 1,        /* input buffer size */
  278.                 0,        /* p3 */
  279.                 0,        /* p4 */
  280.                 0,        /* p5 */
  281.                 0);        /* p6 */
  282.  
  283.         if (!$VMS_STATUS_SUCCESS(status)) {
  284.             ZErMsg(status, 0);
  285.             ErrMsg(ERR_URC);
  286.             exit(EXIT_FAILURE);
  287.         }
  288.  
  289.         switch (ttread_iosb.io_status) {
  290.         case SS$_NORMAL:
  291.         case SS$_ABORT:
  292.             break;
  293.  
  294.         case SS$_CONTROLC:
  295.             return 3;
  296.  
  297.         case SS$_TIMEOUT:
  298.             return -1;
  299.  
  300.         default:
  301.             lib$stop(ttread_iosb.io_status);
  302.         }
  303.         if (Charac == CRETRN) {
  304.             LastCR = TRUE;
  305.         }
  306.     } else {                    /* else not term. */
  307.         if (TIBPtr = TIBERc) {            /* if rec used up */
  308.             status = sys$get(&TIRab);    /* get next record */
  309.             if (status != RMS$_NORMAL) {
  310.                 ZErMsg(status, TIRab.rab$l_stv);
  311.                 ErrMsg(ERR_URC);
  312.                 exit(EXIT_FAILURE);
  313.             }
  314.             TIBERc = &TIBBeg[TIRab.rab$w_rsz];
  315.             *TIBERc++ = CRETRN;
  316.             *TIBERc++ = LINEFD;
  317.             TIBPtr = TIBBeg;
  318.         }
  319.         Charac = *TIBPtr++;
  320.     }
  321.     if (EtFlag & ET_BKSP_IS_DEL) {
  322.         if (Charac == DELETE) {
  323.             Charac = BAKSPC;
  324.         } else if (Charac == BAKSPC) {
  325.             Charac = DELETE;
  326.         }
  327.     }
  328.     return (DEFAULT)Charac;
  329. }
  330.  
  331. /*****************************************************************************
  332.  
  333.     ZClnEG()
  334.  
  335.     This function executes a :EG command.  The :EG commands are used to
  336. get access to operating system functions.  The minimum set of functions is
  337.  
  338.     :EGINI$        gets, sets or clears the initialization file name
  339.     :EGMEM$        gets, sets or clears the file name memory
  340.     :EGLIB$        gets, sets or clears the macro library directory
  341.     :EGVTE$        gets, sets or clears the video macro file name
  342.     :EGSYM$        sets a DCL local symbol (only for VAX/VMS)
  343.  
  344. although more functions may be defined.
  345.  
  346. *****************************************************************************/
  347.  
  348. static SetSym(charptr TxtPtr)        /* set a DCL local symbol */
  349. {
  350.     struct dsc$descriptor_s symbol_desc;
  351.     struct dsc$descriptor_s value_desc;
  352.     unsigned int status;
  353.  
  354.     DBGFEN(1,"SetSym","");
  355.  
  356.     symbol_desc.dsc$b_dtype = value_desc.dsc$b_dtype = DSC$K_DTYPE_T;
  357.     symbol_desc.dsc$b_class = value_desc.dsc$b_class = DSC$K_CLASS_S;
  358.     while (*TxtPtr == ' ') {            /* skip extra spaces */
  359.     if (TxtPtr == '\0') {
  360.         DBGFEX(1,DbgFNm,"1 (supported, but failed)");
  361.         return 1;                /* supported, but failed */
  362.     }
  363.     TxtPtr++;
  364.     }
  365.     symbol_desc.dsc$a_pointer = TxtPtr;        /* find delimiter */
  366.     while (*TxtPtr != ' ') {
  367.     if (TxtPtr == '\0') {
  368.         DBGFEX(1,DbgFNm,"1 (supported, but failed)");
  369.         return 1;                /* supported, but failed */
  370.     }
  371.     TxtPtr++;
  372.     }
  373.     symbol_desc.dsc$w_length = TxtPtr - symbol_desc.dsc$a_pointer;
  374.  
  375.     while (*TxtPtr == ' ') {            /* skip extra spaces */
  376.     if (TxtPtr == '\0') {
  377.         DBGFEX(1,DbgFNm,"1 (supported, but failed)");
  378.         return 1;                /* supported, but failed */
  379.     }
  380.     TxtPtr++;
  381.     }
  382.     value_desc.dsc$w_length = strlen(TxtPtr);
  383.     value_desc.dsc$a_pointer = TxtPtr;
  384.     status = lib$set_symbol(
  385.             &symbol_desc,        /* symbol name */
  386.             &value_desc,        /* value string */
  387.             &LIB$K_CLI_LOCAL_SYM);    /* local or global */
  388.     if (!$VMS_STATUS_SUCCESS(status)) {
  389.     DBGFEX(1,DbgFNm,"supported, but failed");
  390.     return status;                /* return "failed" */
  391.     }
  392.     DBGFEX(1,DbgFNm,"-1 (success)");
  393.     return -1;                    /* return "success" */
  394. }
  395.  
  396. LONG ZClnEG(            /* execute special :EG command */
  397.     DEFAULT EGWhat,        /* what to get/set/clear: MEM, LIB, etc. */
  398.     DEFAULT EGOper,        /* operation: get, set or clear */
  399.     charptr TxtPtr)        /* if setting, null-terminated value to set */
  400. {
  401.     unsigned int status;
  402.     struct dsc$descriptor_s *log_desc;
  403.     static readonly $DESCRIPTOR(mem_desc,"TEC$MEMORY");
  404.     static readonly $DESCRIPTOR(ini_desc,"TEC$INIT");
  405.     static readonly $DESCRIPTOR(lib_desc,"TEC$LIBRARY");
  406.     static readonly $DESCRIPTOR(vte_desc,"TEC$VTEDIT");
  407.  
  408.     DBGFEN(1,"ZClnEG","");
  409.  
  410.     switch (EGWhat) {
  411.     case EG_INI:    log_desc = &ini_desc;    break;
  412.     case EG_LIB:    log_desc = &lib_desc;    break;
  413.     case EG_MEM:    log_desc = &mem_desc;    break;
  414.     case EG_VTE:    log_desc = &vte_desc;    break;
  415.     default:    if (To_Upper(*TxtPtr) == 'S') {
  416.                 TxtPtr++;
  417.                 if (To_Upper(*TxtPtr) == 'Y') {
  418.                 TxtPtr++;
  419.                 if (To_Upper(*TxtPtr) == 'M') {
  420.                     TxtPtr++;
  421.                     if (*TxtPtr == ' ') {
  422.                     return SetSym(++TxtPtr);
  423.                     }
  424.                 }
  425.                 }
  426.             }
  427.             DBGFEX(1,DbgFNm,"0 (unsupported)");
  428.             return 0;
  429.     }
  430.  
  431.     if (EGOper == GET_VAL) {
  432.     short length;
  433.     struct dsc$descriptor_s RSL_desc;
  434.  
  435.     RSL_desc.dsc$w_length  = NAM$C_MAXRSS;
  436.     RSL_desc.dsc$b_dtype   = DSC$K_DTYPE_T;
  437.     RSL_desc.dsc$b_class   = DSC$K_CLASS_S;
  438.     RSL_desc.dsc$a_pointer = FBfBeg;
  439.     status = sys$trnlog(    log_desc,    /* logical name */
  440.                 &length,    /* returned string length */
  441.                 &RSL_desc,    /* returned string buffer */
  442.                 0,        /* logical name table */
  443.                 0,        /* access mode */
  444.                 3);        /* table search mask */
  445.     if (status == SS$_NORMAL) {        /* if it translated */
  446.         FBfPtr = FBfBeg + length;
  447.         *FBfPtr = '\0';            /* null-terminate it */
  448.         DBGFEX(1,DbgFNm,"-1 (success)");
  449.         return -1;                /* return "success" */
  450.     }
  451.     FBfPtr = FBfBeg;            /* nullify the "result" */
  452.     if (!$VMS_STATUS_SUCCESS(status)) {    /* if problem */
  453.         DBGFEX(1,DbgFNm,"supported, but failed");
  454.         return status;            /* return "failed" */
  455.     }
  456.  
  457.     DBGFEX(1,DbgFNm,"-1 (success)");
  458.     return -1;                /* return "success" */
  459.     }
  460.  
  461.     if (EGOper == CLEAR_VAL) {
  462.     status = lib$delete_logical(
  463.                 log_desc,    /* logical name */
  464.                 0);        /* table name */
  465.     } else {
  466.     struct dsc$descriptor_s EQU_desc;
  467.  
  468.     EQU_desc.dsc$w_length  = strlen(TxtPtr);
  469.     EQU_desc.dsc$b_dtype   = DSC$K_DTYPE_T;
  470.     EQU_desc.dsc$b_class   = DSC$K_CLASS_S;
  471.     EQU_desc.dsc$a_pointer = TxtPtr;
  472.     status = lib$set_logical(
  473.                 log_desc,    /* logical name */
  474.                 &EQU_desc);    /* equivalence name */
  475.     }
  476.  
  477.     if (!$VMS_STATUS_SUCCESS(status)) {        /* if not successful */
  478.     DBGFEX(1,DbgFNm,"supported, but failed");
  479.     return status;                /* return "failed" */
  480.     }
  481.  
  482.     DBGFEX(1,DbgFNm,"-1 (success0");
  483.     return -1;                    /* return "success" */
  484. }
  485.  
  486. /*****************************************************************************
  487.  
  488.     ZClnUp()
  489.  
  490.     This function cleans up in preparation for terminating TECO-C.
  491.  
  492. *****************************************************************************/
  493.  
  494. VVOID ZClnUp(void)            /* clean up for exit */
  495. {
  496.     unsigned int status;
  497.  
  498.     DBGFEN(3,"ZClnUp","closing terminal channels and exiting");
  499.     if (TIChan) {                /* if it's a terminal */
  500.         status = sys$dassgn(TIChan);    /* de-assign the channel */
  501.         if (!$VMS_STATUS_SUCCESS(status))
  502.             lib$stop(status);
  503.     } else {                /* else process-perm file */
  504.         status = sys$close(&TIFab);    /* close the file */
  505.         if (status != RMS$_NORMAL) {
  506.             lib$stop(status);
  507.         }
  508.     }
  509.     if (TOChan) {                /* if it's a terminal */
  510.         status = sys$dassgn(TOChan);    /* de-assign the channel */
  511.         if (!$VMS_STATUS_SUCCESS(status)) {
  512.             lib$stop(status);
  513.         }
  514.     } else {                /* else process-perm file */
  515.         if (TOBPtr != TOBBeg) {
  516.             TORab.rab$w_rsz = TOBPtr - TOBBeg;
  517.             status = sys$put(&TORab);    /* output the record */
  518.             if (status != RMS$_NORMAL) {
  519.             lib$stop(status, TORab.rab$l_stv);
  520.             }
  521.         }
  522.         status = sys$close(&TOFab);    /* close the file */
  523.         if (status != RMS$_NORMAL) {
  524.             lib$stop(status);
  525.         }
  526.     }
  527.     if (TCChan) {                /* if it was assigned */
  528.         status = sys$dassgn(TCChan);    /* de-assign the channel */
  529.         if (!$VMS_STATUS_SUCCESS(status)) {
  530.             lib$stop(status);
  531.         }
  532.     }
  533. }
  534.  
  535. #if DEBUGGING
  536. ULONG Zcp2ul(voidptr cp)        /* convert charptr to ULONG */
  537. {
  538.     return (ULONG)(cp);
  539. }
  540. #endif
  541.  
  542. /*****************************************************************************
  543.  
  544.     ZDoCmd()
  545.  
  546.     This function terminates TECO and feeds a command line to the
  547. command line interpreter.  The command to be executed is passed to this
  548. function in the file name buffer (FBf).
  549.  
  550. *****************************************************************************/
  551.  
  552. VVOID ZDoCmd(void)        /* die and pass command to OS */
  553. {
  554.     unsigned int status;
  555.     struct    dsc$descriptor_s CS_descriptor;
  556.  
  557.     DBGFEN(1,"ZDoCmd","");
  558.  
  559.     CS_descriptor.dsc$w_length  = FBfPtr - FBfBeg;
  560.     CS_descriptor.dsc$b_dtype   = DSC$K_DTYPE_T;
  561.     CS_descriptor.dsc$b_class   = DSC$K_CLASS_S;
  562.     CS_descriptor.dsc$a_pointer = FBfBeg;
  563.  
  564.     DBGFEX(1,DbgFNm,"calling lib$do_command");
  565.     status = lib$do_command(&CS_descriptor);
  566.     if (!$VMS_STATUS_SUCCESS(status)) {
  567.         lib$stop(status);
  568.     }
  569. }
  570.  
  571. /*****************************************************************************
  572.  
  573.     ZDspBf()
  574.  
  575.     This function displays a buffer of a given length on the terminal
  576. screen.  On the VAX (and maybe other systems) doing any kind of output
  577. involves a fair amount of overhead,  regardless of the size of the buffer
  578. being output.  It is therefore better to make a single call to the operating
  579. system's output function than to call the function for each and every
  580. character.  If such improvements do not apply to the system this program
  581. is running on,  then this function can simply call ZDspCh for every character
  582. in the buffer.
  583.  
  584. *****************************************************************************/
  585.  
  586. #define MAXTOUT 500
  587.  
  588. VVOID ZDspBf(            /* output a buffer to the terminal */
  589.     charptr buffer,
  590.     SIZE_T length)
  591. {
  592.     int    iolength;
  593.     struct    tt_rw_iosb_struct ttwrite_iosb;
  594.     unsigned int status;
  595.     DEFAULT    TmpLng;
  596.  
  597.     if (TOChan) {                /* if it's a terminal */
  598.         while ((length > 0) && !GotCtC) {
  599.             iolength = (length > MAXTOUT) ? MAXTOUT : length;
  600.             status = sys$qiow(
  601.                 TERM_OUT_EFN,    /* event flag number */
  602.                 TOChan,        /* channel */
  603.                 IO$_WRITEVBLK,    /* I/O func */
  604.                 &ttwrite_iosb,    /* I/O status block */
  605.                 0,        /* AST routine address */
  606.                 0,        /* AST parameter */
  607.                 buffer,        /* p1 */
  608.                 iolength,    /* p2 */
  609.                 0,        /* p3 */
  610.                 0,        /* p4 */
  611.                 0,        /* p5 */
  612.                 0);        /* p6 */
  613.             if (!$VMS_STATUS_SUCCESS(status)) {
  614.                 lib$stop(status);
  615.             }
  616.             if ((!$VMS_STATUS_SUCCESS(ttwrite_iosb.io_status)) &&
  617.                 (ttwrite_iosb.io_status != SS$_ABORT) &&
  618.                 (ttwrite_iosb.io_status != SS$_CONTROLC) &&
  619.                 (ttwrite_iosb.io_status != SS$_CONTROLO)) {
  620.                 lib$stop(ttwrite_iosb.io_status);
  621.             }
  622.             buffer += iolength;
  623.             length -= iolength;
  624.         }
  625.     } else {                /* else it's not a terminal */
  626.         for (TmpLng=1; TmpLng<=length; ++TmpLng) {
  627.             ZDspCh(*buffer++);
  628.         }
  629.     }
  630. }
  631.  
  632. /*****************************************************************************
  633.  
  634.     ZDspCh()
  635.  
  636.     This function outputs a single character to the terminal.
  637.  
  638. *****************************************************************************/
  639.  
  640. VVOID ZDspCh(char Charac)    /* output a character to the terminal */
  641. {
  642.     unsigned int status;
  643.     struct    tt_rw_iosb_struct ttwrite_iosb;
  644.  
  645.     if (TOChan) {                /* if it's a terminal */
  646.         status = sys$qiow(
  647.                 TERM_OUT_EFN,    /* event flag number */
  648.                 TOChan,        /* channel */
  649.                 IO$_WRITEVBLK,    /* I/O func */
  650.                 &ttwrite_iosb,    /* I/O status block */
  651.                 0,        /* AST routine address */
  652.                 0,        /* AST parameter */
  653.                 &Charac,    /* p1 */
  654.                 1,        /* p2 */
  655.                 0,        /* p3 */
  656.                 0,        /* p4 */
  657.                 0,        /* p5 */
  658.                 0);        /* p6 */
  659.  
  660.         if (!$VMS_STATUS_SUCCESS(status)) {
  661.             lib$stop(status);
  662.         }
  663.         if ((!$VMS_STATUS_SUCCESS(ttwrite_iosb.io_status)) &&
  664.              (ttwrite_iosb.io_status != SS$_CONTROLO)) {
  665.             lib$stop(ttwrite_iosb.io_status);
  666.         }
  667.     } else {                /* else it's not a terminal */
  668.         if (IsEOL(Charac)) {
  669.             if (Charac == LINEFD) {
  670.                 if (TOBPtr > TOBBeg) {
  671.                     --TOBPtr;
  672.                     if (*TOBPtr != CRETRN) {
  673.                         ++TOBPtr;
  674.                     }
  675.                 }
  676.             } else {
  677.                 *TOBPtr = Charac;
  678.                 if (++TOBPtr > TOBEnd) {
  679.                     lib$stop(SS$_NORMAL);
  680.                 }
  681.             }
  682.             TORab.rab$w_rsz = TOBPtr - TOBBeg;
  683.             status = sys$put(&TORab);    /* output the record */
  684.             if (status != RMS$_NORMAL) {    /* if it didn't work */
  685.                 lib$stop(status, TORab.rab$l_stv);
  686.             }
  687.             TOBPtr = TOBBeg;
  688.         } else {
  689.             *TOBPtr = Charac;
  690.             if (++TOBPtr > TOBEnd) {
  691.                 lib$stop(SS$_NORMAL);
  692.             }
  693.         }
  694.     }
  695. }
  696.  
  697. /*****************************************************************************
  698.  
  699.     ZEgSym()
  700.  
  701.     This macro gets or sets or clears a CLI symbol.name.  This function
  702. is called to implement the :EGSYM command under VAX/VMS.
  703.  
  704. *****************************************************************************/
  705.  
  706. DEFAULT ZEgSym(SFOpTp,TxtPtr)    /* get/set/clear DCL symbol value */
  707. DEFAULT SFOpTp;
  708. charptr TxtPtr;
  709. {
  710.     unsigned int status;
  711.     struct dsc$descriptor_s Sym_desc = {
  712.         0,                /* dsc$w_length */
  713.         DSC$K_DTYPE_T,            /* dsc$b_dtype */
  714.         DSC$K_CLASS_S,            /* dsc$b_class */
  715.         0                /* dsc$a_pointer */
  716.     };
  717.     struct dsc$descriptor_s Val_desc = {
  718.         NAM$C_MAXRSS,            /* dsc$w_length */
  719.         DSC$K_DTYPE_T,            /* dsc$b_dtype */
  720.         DSC$K_CLASS_S,            /* dsc$b_class */
  721.         FBfBeg                /* dsc$a_pointer */
  722.     };
  723.     short    length;
  724.  
  725.     DBGFEN(1,"ZEgSym","");
  726.  
  727.     Sym_desc.dsc$w_length = FBfPtr-TxtPtr;
  728.     Sym_desc.dsc$a_pointer = TxtPtr;
  729.     if (SFOpTp == GET_VAL) {
  730.         status = lib$get_symbol(
  731.                 &Sym_desc,    /* symbol */
  732.                 &Val_desc,    /* return string buffer */
  733.                 &length,    /* returned string length */
  734.                 0);        /* table indicator */
  735.         if (!$VMS_STATUS_SUCCESS(status)) { /* if something is wrong */
  736.             FBfPtr = FBfBeg;    /* nullify the "result" */
  737.             DBGFEX(1,DbgFNm,"");
  738.             return status;        /* return "failed" */
  739.         }
  740.         FBfPtr = FBfBeg + length;
  741.         *FBfPtr = '\0';
  742.         DBGFEX(1,DbgFNm,"-1");
  743.         return -1;            /* return "success" */
  744.     }
  745.  
  746.     if (SFOpTp == CLEAR_VAL) {
  747.         Val_desc.dsc$w_length = 0;
  748.     } else {
  749.         Val_desc.dsc$w_length = FBfPtr-TxtPtr;
  750.     }
  751.     Val_desc.dsc$a_pointer = TxtPtr;
  752.  
  753.     status = lib$set_symbol(&Sym_desc,    /* symbol */
  754.                 &Val_desc,    /* value */
  755.                 0);        /* table indicator */
  756.     if (!$VMS_STATUS_SUCCESS(status)) {
  757.         DBGFEX(1,DbgFNm,"");
  758.         return status;            /* return "failed" */
  759.     }
  760.  
  761.     DBGFEX(1,DbgFNm,"-1");
  762.     return -1;                /* return "success" */
  763. }
  764.  
  765. /*****************************************************************************
  766.  
  767.     ZExCtB()
  768.  
  769.     This function implements the TECO ^B command,  which returns the
  770. current date encoded in the following way:
  771.  
  772.         ((year-1900)*16+month)*32+day
  773.  
  774. *****************************************************************************/
  775.  
  776. DEFAULT ZExCtB(void)            /* return current date */
  777. {
  778.     unsigned int status;
  779.     short    system_time[7];
  780.     LONG    teco_date;
  781.  
  782.     DBGFEN(1,"ZExCtB","");
  783.     status = sys$numtim(    system_time,        /* returned time */
  784.                 0);            /* time to convert */
  785.     if (!$VMS_STATUS_SUCCESS(status)) {
  786.         lib$stop(status);
  787.     }
  788.  
  789.     teco_date = (system_time[0] - 1900) << 4;    /* (year-1900) * 16 */
  790.     teco_date += system_time[1];            /* month */
  791.     teco_date = teco_date << 5;            /* multiply by 32 */
  792.     teco_date += system_time[2];            /* day of month */
  793.  
  794.     DBGFEX(1,DbgFNm,"PushEx()");
  795.     return PushEx(teco_date, OPERAND);
  796. }
  797.  
  798. /*****************************************************************************
  799.  
  800.     ZExCtH()
  801.  
  802.     This function implements the TECO ^H command,  which returns the
  803. current time encoded in the following way:
  804.  
  805.         (seconds since midnight) / 2
  806.  
  807. *****************************************************************************/
  808.  
  809. DEFAULT ZExCtH(void)            /* return current time */
  810. {
  811.     unsigned int status;
  812.     short    system_time[7];
  813.     LONG    teco_time;
  814.  
  815.     DBGFEN(1,"ZExCtH","");
  816.     status = sys$numtim(    system_time,    /* returned time */
  817.                 0);        /* time to convert */
  818.     if (!$VMS_STATUS_SUCCESS(status)) {
  819.         lib$stop(status);
  820.     }
  821.  
  822.     teco_time = system_time[3] * 60;    /* hours * 60 */
  823.     teco_time += system_time[4];        /* minutes */
  824.     teco_time *= 30;
  825.     teco_time += system_time[5] >> 1;    /* seconds / 2 */
  826.  
  827.     DBGFEX(1,DbgFNm,"PushEx()");
  828.     return PushEx(teco_time, OPERAND);
  829. }
  830.  
  831. /*****************************************************************************
  832.  
  833.     ZExeEJ()
  834.  
  835.     This function executes an EJ command,  which returns environment
  836. characteristics.  It returns:
  837.  
  838.     -1EJ    1024 under VAX/VMS    (4*256 = VAX, 0 = VMS in native mode)
  839.         1025 under Ultrix    (4*256 = VAX, 1 = Ultrix)
  840.         25600 under Sun/SunOS    (100*256 = Sun, 0 = SunOS)
  841.         25856 under MS-DOS    (101*256 = IBM-PC, 0 = MS-DOS)
  842.  
  843.     0EJ    process id on VAXen, 0 on anything else
  844.  
  845.     1EJ    0 on all systems
  846.  
  847.     2EJ    UIC, in longword format (unlike TECO-11) on VAX/VMS,
  848.         0 on all other systems.
  849.  
  850. *****************************************************************************/
  851.  
  852. DEFAULT ZExeEJ(void)            /* execute an EJ command */
  853. {
  854.     LONG    RetVal;
  855.  
  856.     DBGFEN(1,"ZExeEJ","");
  857.     if (EStTop == EStBot) {            /* if no numeric argument */
  858.         NArgmt = 0;            /* default is 0EJ */
  859.     } else {
  860.         UMinus();            /* if -EJ, make it -1EJ */
  861.         if (GetNmA() == FAILURE) {    /* get numeric argument */
  862.             DBGFEX(1,DbgFNm,"FAILURE");
  863.             return FAILURE;
  864.         }
  865.     }
  866.  
  867.     if (NArgmt < 0) {            /* oper. system dependent */
  868.         if (NArgmt == -1) {
  869.             RetVal = 1024;        /* means "VAX running VMS" */
  870.         } else {
  871.             return ExeNYI();
  872.         }
  873.     } else if (NArgmt == 1) {        /* 1EJ (terminal unit) */
  874.         RetVal = 0;
  875.     } else {
  876.         struct getxxx_iosb_struct getjpi_iosb;
  877.         struct {
  878.             short    buflen1;    /* buffer length */
  879.             short    itmcode1;    /* item code */
  880.             charptr    buffer1;    /* buffer address */
  881.             short    *retlen1;    /* returned length */
  882.             int    termin;        /* item list terminator */
  883.         } item_list = {
  884.                 4,        /* buffer length */
  885.                 JPI$_UIC,    /* uic (2EJ) */
  886.                 &RetVal,    /* buffer address */
  887.                 0,        /* returned length */
  888.                 0        /* item list terminator */
  889.         };
  890.         unsigned int status;
  891.  
  892.         if (NArgmt == 0) {            /* 0EJ (process id) */
  893.             item_list.itmcode1 = JPI$_PID;
  894.         }
  895.         status = sys$getjpiw(    0,        /* event flag */
  896.                     0,        /* pid address */
  897.                     0,        /* process name */
  898.                     &item_list,    /* item list */
  899.                     &getjpi_iosb,    /* i/o status block */
  900.                     0,        /* AST routine */
  901.                     0);        /* AST parameter */
  902.         if (!$VMS_STATUS_SUCCESS(status)) {
  903.             lib$stop(status);
  904.         }
  905.         if (!$VMS_STATUS_SUCCESS(getjpi_iosb.io_status)) {
  906.             lib$stop(getjpi_iosb.io_status);
  907.         }
  908.     }
  909.  
  910.     DBGFEX(1,DbgFNm,"PushEx()");
  911.     return PushEx(RetVal,OPERAND);
  912. }
  913.  
  914. /*****************************************************************************
  915.  
  916.     ZExit()
  917.  
  918.     This function terminates TECO-C with a status value.
  919.  
  920. *****************************************************************************/
  921.  
  922. VVOID ZExit(DEFAULT estat)        /* terminate TECO-C */
  923. {
  924. /*
  925.  * Exit with a success status if we're exiting normally.  If we're exiting
  926.  * because something went wrong,  then exit with a VMS error status.  Since
  927.  * we don't have a message file, just steal a system-defined code (ABORT)
  928.  * which is somewhat meaningful.
  929.  */
  930.  
  931.     sys$exit((estat == EXIT_SUCCESS) ? SS$_NORMAL : SS$_ABORT);
  932. }
  933.  
  934. /*****************************************************************************
  935.  
  936.     ZFree()
  937.  
  938.     This function frees memory previously allocated by the ZAlloc
  939. function.
  940.  
  941. *****************************************************************************/
  942.  
  943. VVOID ZFree(voidptr pointer)        /* free memory allocated by ZAlloc */
  944. {
  945.     free(pointer);
  946. }
  947.  
  948. /*****************************************************************************
  949.  
  950.     ZHelp()
  951.  
  952.     This function accepts a help string and displays the corresponding
  953. help text.
  954.  
  955.     it should be control-C interrupt-able.
  956.  
  957. *****************************************************************************/
  958.  
  959. /*****************************************************************************
  960.     Help on the VAX is accessed through the help library routines.
  961. *****************************************************************************/
  962.  
  963. VVOID ZHelp(            /* display a help message */
  964.     charptr HlpBeg,        /* first char of help request */
  965.     charptr HlpEnd,        /* last character of help request */
  966.     BOOLEAN SysLib,        /* use default HELP library? */
  967.     BOOLEAN    Prompt)        /* enter interactive help mode? */
  968. {
  969.     struct dsc$descriptor_s line_desc;
  970.     struct dsc$descriptor_s lib_desc;
  971.     unsigned int    flags;
  972.     unsigned int    status;
  973.     $DESCRIPTOR(syshelp_desc, "SYS$HELP:HELPLIB");
  974.     $DESCRIPTOR(techelp_desc, "TEC$HELP");
  975. #if DEBUGGING
  976.     static char *DbgFNm = "ZHelp";
  977.     sprintf(DbgSBf,"text = \"%.*s\"", (int)(HlpEnd-HlpBeg), HlpBeg);
  978.     DbgFEn(2,DbgFNm,DbgSBf);
  979. #endif
  980.  
  981.     line_desc.dsc$a_pointer = HlpBeg;
  982.     line_desc.dsc$w_length = (HlpEnd - HlpBeg) + 1;
  983.  
  984.     lib_desc = (SysLib ? syshelp_desc : techelp_desc);
  985.  
  986.     flags = HLP$M_PROCESS | HLP$M_GROUP | HLP$M_SYSTEM | HLP$M_HELP;
  987.     if (Prompt) {
  988.         flags |= HLP$M_PROMPT;
  989.     }
  990.  
  991.     status = lbr$output_help(    lib$put_output,    /* output routine */
  992.                     0,        /* output width */
  993.                     &line_desc,    /* line-desc */
  994.                     &lib_desc,    /* library name */
  995.                     &flags,        /* flags */
  996.                     lib$get_input);    /* input rotuine */
  997.     if (status != SS$_NORMAL) {
  998.         ZErMsg(status,0);
  999.     }
  1000.  
  1001.     DBGFEX(2,DbgFNm,"");
  1002. }
  1003.  
  1004. /*****************************************************************************
  1005.  
  1006.     ZIClos()
  1007.  
  1008.     This function closes the current input file.  It must
  1009.  
  1010.     1.  if current input stream is not open,  simply return
  1011.     2.  close the input file
  1012.     3.  set open indicator to FALSE
  1013.  
  1014. *****************************************************************************/
  1015.  
  1016. VVOID ZIClos(DEFAULT IfIndx)        /* close input file */
  1017. {
  1018.     unsigned int status;
  1019.  
  1020.     DBGFEN(2,"ZIClos","");
  1021.  
  1022.     if (IsOpnI[IfIndx]) {            /* if it's open */
  1023.         status = sys$close(&IFiles[IfIndx].IFab);
  1024.         if (status != RMS$_NORMAL) {
  1025.             ZErMsg(status, IFiles[IfIndx].IFab.fab$l_stv);
  1026.             if (!$VMS_STATUS_SUCCESS(status)) {
  1027.                 ErrMsg(ERR_UCI);
  1028. #if DEBUGGING
  1029.                 DbgFMs(2,DbgFNm,"dying");
  1030. #endif
  1031.                 exit(EXIT_FAILURE);
  1032.             }
  1033.         }
  1034.         IsOpnI[IfIndx] = FALSE;
  1035.     }
  1036.  
  1037.     DBGFEX(2,DbgFNm,"");
  1038. }
  1039.  
  1040. /*****************************************************************************
  1041.  
  1042.     ZOClDe()
  1043.  
  1044.     This function closes and deletes the current output stream.  It must
  1045.  
  1046.     1.  if no current output stream is defined,  simply return
  1047.     2.  close the output stream
  1048.     3.  delete the file just closed
  1049.  
  1050. *****************************************************************************/
  1051.  
  1052. VVOID ZOClDe(DEFAULT OfIndx)        /* close and delete output file */
  1053. {
  1054.     unsigned int status;
  1055.  
  1056.     DBGFEN(2,"ZOClDe","");
  1057.  
  1058.     if (IsOpnO[OfIndx]) {        /* if output stream is open */
  1059.         OFiles[OfIndx].OFab.fab$l_fop |= FAB$M_DLT;
  1060.         status = sys$close(&OFiles[OfIndx].OFab);
  1061.         if (status != RMS$_NORMAL) {
  1062.             ZErMsg(status, OFiles[OfIndx].OFab.fab$l_stv);
  1063.             if (!$VMS_STATUS_SUCCESS(status)) {
  1064.                 ErrMsg(ERR_UCD);
  1065.                 exit(EXIT_FAILURE);
  1066.             }
  1067.         }
  1068.         IsOpnO[OfIndx] = FALSE;
  1069.     }
  1070.  
  1071.     DBGFEX(2,DbgFNm,"");
  1072. }
  1073.  
  1074. /*****************************************************************************
  1075.  
  1076.     ZOClos()
  1077.  
  1078.     This function closes the current output stream.  It is only called
  1079. when an output stream is defined.  It must
  1080.  
  1081.     1.  flush output to the stream,  if neccessary
  1082.     2.  close the stream
  1083.     3.  set OFile to -1
  1084.  
  1085. *****************************************************************************/
  1086.  
  1087. VVOID ZOClos(DEFAULT OfIndx)    /* close output file */
  1088. {
  1089.     unsigned int status;
  1090.  
  1091.     DBGFEN(2,"ZOClos","");
  1092.  
  1093.     if (IsOpnO[OfIndx]) {            /* if it's open */
  1094.         status = sys$close(&OFiles[OfIndx].OFab);
  1095.         if (status != RMS$_NORMAL) {
  1096.             ZErMsg(status, OFiles[OfIndx].OFab.fab$l_stv);
  1097.             if (!$VMS_STATUS_SUCCESS(status)) {
  1098.                 ErrMsg(ERR_UCO);
  1099.                 exit(EXIT_FAILURE);
  1100.             }
  1101.         }
  1102.         IsOpnO[OfIndx] = FALSE;
  1103.     }
  1104.  
  1105.     DBGFEX(2,DbgFNm,"");
  1106. }
  1107.  
  1108. /*****************************************************************************
  1109.  
  1110.     ZOpInp()
  1111.  
  1112.     This function opens an input file.  The name of the file is pointed
  1113. to by FBfBeg.  FBfPtr points to the character following the last character of
  1114. the file name.
  1115.     This function is used to open all files,  including macro files
  1116. needed by the "EI" command.  The "EIFlag" argument tells this function if
  1117. it's an "EI" file.  If it is,  some extra file searching is done to make
  1118. things convenient for the user.  The extra processing is modelled after what
  1119. happens under VMS (or really,  what SHOULD happen under VMS).  The basic idea
  1120. is to find the macro file whether the user has specificed the ".tec" or not,
  1121. and whether it's in the current directory or the macro library directory.
  1122. The basic Unix logic is like this:
  1123.  
  1124.     if (the file exists)
  1125.         open it and return SUCCESS
  1126.     if (EIfile) {
  1127.         if (there's no dot and appending ".tec" works)
  1128.         open it and return SUCCESS
  1129.         if (prepending default library directory works)
  1130.         open it and return SUCCESS
  1131.         if (prepending library and appending ".tec" works)
  1132.         open it and return SUCCESS
  1133.     }
  1134.     file not found, so return with error
  1135.  
  1136. Under VAX/VMS,  it's a little different.  VMS tries to open the file only
  1137. twice,  each time with the RMS "default type" field set to ".TEC",  so VMS
  1138. will insert ".TEC" if the user doesn't.  There's no straightforward way to
  1139. avoid putting ".TEC" on the end of your TECO macro file namess under VMS,
  1140. which some would argue is a good thing,  as long as you don't have to type
  1141. the ".TEC" when you use them.
  1142.  
  1143. Under MS-DOS,  the above PDL works,  except that when the logic talks about
  1144. appending ".tec",  it doesn't happen if there's alreay a dot in the file
  1145. name,  as you can only have one dot in MS-DOS file names.
  1146.  
  1147. *****************************************************************************/
  1148.  
  1149. DEFAULT    ZOpInp(            /* open input file */
  1150.     DEFAULT IfIndx,        /* index into file data block array IFiles */
  1151.     BOOLEAN    EIFile,        /* is it a macro file? (hunt for it) */
  1152.     BOOLEAN RepFNF)        /* report "file not found" error? */
  1153. {
  1154.     char    ExpFBf[NAM$C_MAXRSS];    /* expanded filename buffer */
  1155.     struct    FAB    *IF;        /* pointer to FAB */
  1156.     struct    NAM    *IN;        /* pointer to NAM block */
  1157.     struct    RAB    *IR;        /* pointer to RAB */
  1158.     unsigned int status;        /* temporary status */
  1159.  
  1160. #if DEBUGGING
  1161.     static char *DbgFNm = "ZOpInp";
  1162.     sprintf(DbgSBf,", FBf = \"%.*s\"", (int)(FBfPtr-FBfBeg), FBfBeg);
  1163.     DbgFEn(2,DbgFNm,DbgSBf);
  1164. #endif
  1165.  
  1166.     IN = &IFiles[IfIndx].INam;
  1167.     *IN = cc$rms_nam;            /* initialize NAM defaults */
  1168.     IN->nam$l_esa = ExpFBf;        /* expanded file spec buffer addr. */
  1169.     IN->nam$b_ess = sizeof ExpFBf;    /* expanded file spec buffer size */
  1170.     IN->nam$l_rsa = FBfBeg;        /* resultant file spec buffer addr. */
  1171.     IN->nam$b_rss = NAM$C_MAXRSS;    /* resultant file spec buffer size */
  1172.  
  1173.     IF = &IFiles[IfIndx].IFab;
  1174.     *IF = cc$rms_fab;            /* initialize FAB defaults */
  1175.     IF->fab$l_nam = IN;            /* address of NAM block */
  1176.     IF->fab$b_fac = FAB$M_GET;        /* file access = read only */
  1177.     IF->fab$b_shr = FAB$M_SHRGET;    /* allow others to read the file */
  1178.     if (EIFile) {            /* if use default file type ".TEC" */
  1179.     IF->fab$l_dna = ".TEC";        /* default filename */
  1180.     IF->fab$b_dns = 4;        /* default filename size */
  1181.     }
  1182.     IF->fab$l_fna = FBfBeg;        /* set file name address */
  1183.     IF->fab$b_fns = FBfPtr - FBfBeg;    /* set file name size */
  1184.  
  1185.     IR = &IFiles[IfIndx].IRab;
  1186.     *IR = cc$rms_rab;            /* initialize RAB defaults */
  1187.     IR->rab$l_fab = IF;            /* address of associated FAB */
  1188.     IR->rab$b_rac = RAB$C_SEQ;        /* record access mode = sequential */
  1189.  
  1190.     status = sys$open(IF);        /* open the file */
  1191.     if (status != RMS$_NORMAL) {    /* if failed for some reason */
  1192.     if ((status == RMS$_FNF) && EIFile) {    /* if couldn't find EI file */
  1193.         charptr dummyp = NULL;
  1194.         char TmpBfr[NAM$C_MAXRSS];
  1195.         ptrdiff_t TmpLen = FBfPtr-FBfBeg;
  1196.  
  1197.         MEMMOVE(TmpBfr, FBfBeg, TmpLen);    /* save file name */
  1198.         if (ZClnEG(EG_LIB, GET_VAL, dummyp) != -1) {  /* get dir spec */
  1199.         goto open_failed;
  1200.         }
  1201.         MEMMOVE(FBfPtr, TmpBfr, TmpLen);    /* append name to dir spec */
  1202.         FBfPtr += TmpLen;
  1203.         IF->fab$b_fns = FBfPtr - FBfBeg;    /* set file name size */
  1204.         status = sys$open(IF);        /* open the file */
  1205.         if (status != RMS$_NORMAL) {
  1206.         goto open_failed;
  1207.         }
  1208.     } else {
  1209. open_failed:
  1210.         if (!RepFNF && (status == RMS$_FNF)) {
  1211.             DBGFEX(2,DbgFNm,"FILENF");
  1212.         return FILENF;
  1213.         }
  1214.         ZErMsg(status, IF->fab$l_stv);
  1215.         if (!$VMS_STATUS_SUCCESS(status)) {
  1216.             DBGFEX(2,DbgFNm,"FAILURE");
  1217.         return FAILURE;
  1218.         }
  1219.     }
  1220.     }
  1221.  
  1222.     FBfPtr = FBfBeg + IN->nam$b_rsl;        /* resultant name length */
  1223.  
  1224.     status = sys$connect(IR);            /* connect RAB to FAB */
  1225.     if (status != RMS$_NORMAL) {
  1226.     ZErMsg(status, IR->rab$l_stv);
  1227.     if (!$VMS_STATUS_SUCCESS(status)) {
  1228.         status = sys$close(IF);        /* close the file */
  1229.             DBGFEX(2,DbgFNm,"FAILURE");
  1230.             return FAILURE;
  1231.     }
  1232.     }
  1233.     IFiles[IfIndx].leftover_input_exists = FALSE;
  1234.  
  1235.     DBGFEX(2,DbgFNm,"SUCCESS");
  1236.     return SUCCESS;
  1237. }
  1238.  
  1239. /*****************************************************************************
  1240.  
  1241.     ZOpOut()
  1242.  
  1243.     This function creates (and opens) an output file.  The name of
  1244. the file to be created is pointed to by FBfBeg.  FBfPtr points to the
  1245. character following the last character of the file name.
  1246.  
  1247. *****************************************************************************/
  1248.  
  1249. DEFAULT ZOpOut(DEFAULT OfIndx, BOOLEAN RepErr)    /* open output file */
  1250. {
  1251.     char    ExpFBf[NAM$C_MAXRSS];    /* expanded filename buffer */
  1252.     struct    FAB    *OF;
  1253.     struct    NAM    *ON;
  1254.     struct    RAB    *OR;
  1255.     unsigned int status;
  1256.  
  1257. #if DEBUGGING
  1258.     static char *DbgFNm = "ZOpOut";
  1259.     sprintf(DbgSBf,", FBf = \"%.*s\"",(int)(FBfPtr-FBfBeg),FBfBeg);
  1260.     DbgFEn(2,DbgFNm,DbgSBf);
  1261. #endif
  1262.  
  1263.     ON = &OFiles[OfIndx].ONam;
  1264.     *ON = cc$rms_nam;        /* initialize NAM defaults */
  1265.     ON->nam$l_esa = ExpFBf;        /* expanded file spec buffer address */
  1266.     ON->nam$b_ess = sizeof ExpFBf;    /* expanded file spec buffer size */
  1267.     ON->nam$l_rsa = FBfBeg;        /* resultant file spec buffer address */
  1268.     ON->nam$b_rss = NAM$C_MAXRSS;    /* resultant file spec buffer size */
  1269.  
  1270.     OF = &OFiles[OfIndx].OFab;
  1271.     *OF = cc$rms_fab;        /* initialize FAB defaults */
  1272.     OF->fab$b_fac = FAB$M_PUT;    /* file access = write only */
  1273.     OF->fab$b_org = FAB$C_SEQ;    /* file organization = sequential */
  1274.     OF->fab$b_rat = FAB$M_CR;    /* carriage return record attribute */
  1275.     OF->fab$b_rfm = FAB$C_VAR;    /* variable length record format */
  1276.     OF->fab$b_shr = FAB$M_NIL;    /* no sharing */
  1277.     OF->fab$l_nam = ON;        /* address of NAM block */
  1278.     OF->fab$l_fna = FBfBeg;        /* file name address */
  1279.     OF->fab$b_fns = FBfPtr - FBfBeg;    /* file name size */
  1280.  
  1281.     OR = &OFiles[OfIndx].ORab;
  1282.     *OR = cc$rms_rab;        /* initialize RAB defaults */
  1283.     OR->rab$l_fab = OF;        /* address of associated FAB */
  1284.     OR->rab$b_rac = RAB$C_SEQ;    /* record access mode = sequential */
  1285.  
  1286.     status = sys$create(OF);        /* create the file */
  1287.     if (status != RMS$_NORMAL) {
  1288.         if (RepErr) {
  1289.             ZErMsg(status, OF->fab$l_stv);
  1290.         }
  1291.         if (!$VMS_STATUS_SUCCESS(status)) {
  1292.             DBGFEX(2,DbgFNm,"FAILURE, sys$create failed");
  1293.             return FAILURE;
  1294.         }
  1295.     }
  1296.  
  1297.     FBfPtr = FBfBeg + ON->nam$b_rsl;    /* resultant name length */
  1298.  
  1299.     status = sys$connect(OR);        /* connect RAB to FAB */
  1300.     if (status != RMS$_NORMAL) {
  1301.         if (RepErr) {
  1302.             ZErMsg(status, OR->rab$l_stv);
  1303.         }
  1304.         if (!$VMS_STATUS_SUCCESS(status)) {
  1305.             OF->fab$l_fop |= FAB$M_DLT;    /* delete on close */
  1306.             status = sys$close(OF);        /* close the file */
  1307.             DBGFEX(2,DbgFNm,"FAILURE, sys$connect failed");
  1308.             return FAILURE;
  1309.         }
  1310.     }
  1311.  
  1312.     DBGFEX(2,DbgFNm,"SUCCESS");
  1313.     return SUCCESS;
  1314. }
  1315.  
  1316. /*****************************************************************************
  1317.  
  1318.     ZPrsCL()
  1319.  
  1320.     This function parses the command line.  It does so using the classic
  1321. TECO-11 method:  use a TECO macro to do it!  The macros is stored in array
  1322. "clpars".  The macro is in file "clpars.h",  and is over 3k long.  The VMS C
  1323. compiler (version 3.0) can't handle a string literal that's that long, so
  1324. it loads a piece of memory 1 line at a time.
  1325.  
  1326. *****************************************************************************/
  1327.  
  1328. /*
  1329.   Under VAX/VMS,  the logic is:
  1330.  
  1331.     load q-register Z with the command line
  1332.     load q-register Y with a command-line parsing macro
  1333.     IF logical name "TECO" is defined THEN
  1334.         do an EITECO$$
  1335.     ELSEIF the file "SYS$LOGIN:TECO.TEC" exists, THEN
  1336.         do an EISYS$LOGIN:TECO.TEC$$
  1337.     ELSE
  1338.         do an MY$$
  1339. */
  1340.  
  1341. VVOID ZPrsCL(            /* parse the command line */
  1342.     int argc,
  1343.     char *argv[])
  1344. {
  1345.     char    MngBeg[4+NAM$C_MAXRSS];    /* temporary command string buffer */
  1346.     charptr    MngPtr;            /* pointer into mung buffer */
  1347.     charptr    TmpPtr;            /* temporary pointer */
  1348.     BOOLEAN filefound;
  1349.     short    length;
  1350.     unsigned int status;
  1351.     char    CLPars_name[NAM$C_MAXRSS];
  1352.     $DESCRIPTOR(teco_desc,"TECO");
  1353.     $DESCRIPTOR(fil_desc,"SYS$LOGIN:TECO.TEC");
  1354.     $DESCRIPTOR(res_desc, CLPars_name);
  1355.     int    i;
  1356.     SIZE_T    line_len;
  1357.     char    cmd_line[1024];
  1358.     $DESCRIPTOR(cmd_line_desc, cmd_line);
  1359.  
  1360.     DBGFEN(2,"ZPrsCL","");
  1361.  
  1362. /*
  1363.  * If the command line contains arguments,  load them into Q-register Z.
  1364.  */
  1365.  
  1366.     status = lib$get_foreign(        /* get command line */
  1367.         &cmd_line_desc,            /* returned string */
  1368.         0,                /* user prompt */
  1369.         &cmd_line_desc.dsc$w_length,    /* returned string length */
  1370.         0);                /* force prompt */
  1371.     if (!$VMS_STATUS_SUCCESS(status)) {
  1372.         lib$stop(status);
  1373.     }
  1374.     if (cmd_line_desc.dsc$w_length != 0) {
  1375.         QR = &QRgstr[35];        /* 35 = q-register Z */
  1376.         if (MakRom((SIZE_T)cmd_line_desc.dsc$w_length) == FAILURE)
  1377.             exit(EXIT_FAILURE);
  1378.         MEMMOVE(QR->Start,            /* destination */
  1379.             cmd_line,            /* source */
  1380.             cmd_line_desc.dsc$w_length);    /* length */
  1381.         QR->End_P1 += cmd_line_desc.dsc$w_length;
  1382.     }
  1383.  
  1384. /*
  1385.  * load imbedded command-line parsing macro into q-register Y
  1386.  */
  1387.  
  1388.     QR = &QRgstr[34];            /* 34 = q-register Y */
  1389.     if (MakRom((SIZE_T)CLPARS_LEN) == FAILURE) {
  1390.         exit(EXIT_FAILURE);
  1391.     }
  1392.     for (i=0; i<CLPARS_LINES; i++) {
  1393.         line_len = strlen(clpars[i]);
  1394.         MEMMOVE(QR->End_P1, clpars[i], line_len);
  1395.         QR->End_P1 += line_len;        /* length of q-reg text */
  1396.     }
  1397.  
  1398. /*
  1399.  * If the logical name "TECO" is defined,  then do EITECO$$.  If not,  look
  1400.  * for file SYS$LOGIN:TECO.TEC, and "EI" it if it exists. If it also doesn't
  1401.  * exist,  just execute the macro in q-register Y.
  1402.  */
  1403.  
  1404.     status = sys$trnlog(    &teco_desc,    /* logical name */
  1405.                 &length,    /* returned string length */
  1406.                 &res_desc,    /* returned string buffer */
  1407.                 0,        /* logical name table */
  1408.                 0,        /* access mode */
  1409.                 3);        /* table search mask */
  1410.     if (status == SS$_NORMAL) {        /* if logical exists */
  1411.         filefound = TRUE;        /* do EITECO$$ later*/
  1412.     } else if (status == SS$_NOTRAN) {    /* if logical doesn't exist */
  1413.         int    context;
  1414.         int    user_flags;
  1415.  
  1416.         context = 0;
  1417.         user_flags = 1;
  1418.         status = lib$find_file(    &fil_desc,    /* file spec */
  1419.                     &res_desc,    /* resultant spec */
  1420.                     &context,    /* context */
  1421.                     0,        /* default spec */
  1422.                     0,        /* related spec */
  1423.                     0,        /* stv address */
  1424.                     &user_flags);    /* user flags */
  1425.         if (status == RMS$_NORMAL) {
  1426.             length = res_desc.dsc$w_length;
  1427.             filefound = TRUE;
  1428.         } else {
  1429.             if (status != RMS$_FNF) {
  1430.                 if (!$VMS_STATUS_SUCCESS(status)) {
  1431.                     lib$stop(status);
  1432.                 }
  1433.             }
  1434.             filefound = FALSE;
  1435.         }
  1436.         status = lib$find_file_end(&context);
  1437.         if (!$VMS_STATUS_SUCCESS(status)) {
  1438.             lib$stop(status);
  1439.         }
  1440.     } else {
  1441.         lib$stop(status);        /* terminate */
  1442.     }
  1443.  
  1444. /*
  1445.  * If there is a user-defined command-parsing macro file,  do an EI on it.
  1446.  * Otherwise,  execute q-register Y.
  1447.  */
  1448.  
  1449.     MngPtr = MngBeg;
  1450.     if (filefound) {
  1451.         *MngPtr++ = 'e';
  1452.         *MngPtr++ = 'i';
  1453.         TmpPtr = res_desc.dsc$a_pointer;
  1454.         for (;length>0;length--) {
  1455.             *MngPtr++ = *TmpPtr++;
  1456.         }
  1457.     } else {
  1458.         *MngPtr++ = 'm';
  1459.         *MngPtr++ = 'y';
  1460.     }
  1461.     *MngPtr++ = ESCAPE;
  1462.     *MngPtr = ESCAPE;
  1463.     CBfPtr = MngBeg;            /* command string start */
  1464.     CStEnd = MngPtr;            /* command string end */
  1465.     EStTop = EStBot;            /* clear expression stack */
  1466.     ExeCSt();                /* execute command string */
  1467.     DBGFEX(2,DbgFNm,"");
  1468. }
  1469.  
  1470. /*****************************************************************************
  1471.  
  1472.     ZPWild()
  1473.  
  1474.     This function presets the wildcard lookup filename.  It is called
  1475. when the user executes an ENfilename$ command.  Later executions of the EN$
  1476. command will cause the ZSWild function to be called to return successive
  1477. wildcard matches.
  1478.  
  1479. *****************************************************************************/
  1480.  
  1481. DEFAULT ZPWild(void)        /* preset the wildcard lookup filename */
  1482. {
  1483.     unsigned int status;
  1484.     static BOOLEAN first_time_called = TRUE;
  1485.  
  1486. #if DEBUGGING
  1487.     static char *DbgFNm = "ZPWild";
  1488.     sprintf(DbgSBf, ", FBf = \"%.*s\"", (int)(FBfPtr-FBfBeg), FBfBeg);
  1489.     DbgFEn(1,DbgFNm,DbgSBf);
  1490. #endif
  1491.  
  1492.     if (first_time_called) {
  1493.         first_time_called = FALSE;
  1494.         WNam = cc$rms_nam;        /* initialize NAM defaults */
  1495.         WNam.nam$l_esa = WBfExp;    /* expanded file spec buf */
  1496.         WNam.nam$b_ess = NAM$C_MAXRSS;    /* expanded f. s. buf size */
  1497.         WNam.nam$l_rsa = FBfBeg;    /* res file spec buf */
  1498.         WNam.nam$b_rss = NAM$C_MAXRSS;    /* res file spec buf size */
  1499.         WFab = cc$rms_fab;        /* initialize FAB defaults */
  1500.         WFab.fab$l_fna = FBfBeg;    /* addr. wildcard file spec */
  1501.         WFab.fab$l_nam = &WNam;        /* address of NAM block */
  1502.         WFab.fab$b_fac = FAB$M_GET;    /* file access = read only */
  1503.     }
  1504.  
  1505.     WFab.fab$b_fns = FBfPtr - FBfBeg;    /* file name size */
  1506.  
  1507.     status = sys$parse(&WFab);
  1508.     if (status != RMS$_NORMAL) {
  1509.         ZErMsg(status, WFab.fab$l_stv);
  1510.         if (!$VMS_STATUS_SUCCESS(status)) {
  1511.             DBGFEX(1,DbgFNm,"FAILURE");
  1512.             return FAILURE;
  1513.         }
  1514.     }
  1515.  
  1516.     DBGFEX(1,DbgFNm,"SUCCESS");
  1517.     return SUCCESS;
  1518. }
  1519.  
  1520. /*****************************************************************************
  1521.  
  1522.     ZRaloc()
  1523.  
  1524.     This function performs the standard C library function realloc.
  1525.  
  1526. *****************************************************************************/
  1527.  
  1528. voidptr    ZRaloc(voidptr OldBlk, SIZE_T NewSiz)
  1529. {
  1530.     return realloc(OldBlk, NewSiz);
  1531. }
  1532.  
  1533. /*****************************************************************************
  1534.  
  1535.     ZRdLin()
  1536.  
  1537.         This function reads a line from a file.  It is passed a buffer, the
  1538. size of the buffer, a file pointer and a pointer to a place to leave the
  1539. length of the line.
  1540.  
  1541.     What this function does may be confusing, so here's a description
  1542. of it from the Standard TECO manual, Appendix G (VAX/VMS Operating
  1543. Characteristics), section 11: "File Record Format".  TECO-C supports only
  1544. implied-carriage-control files under VMS,  so I removed the discussion of
  1545. other formats.
  1546.  
  1547.      Files-11 files are record structured, while TECO'S text buffer is
  1548.      ASCII stream.   Thus TECO must make format conversions when reading
  1549.      and writing files.  While reading a file, the records are packed
  1550.      into the buffer.  TECO inserts a carriage return and line feed
  1551.      after each record to make each record appear as a line of text in
  1552.      the buffer, unless the record ends with ESCAPE, carriage return,
  1553.      line feed, vertical tab, or form feed.  A record ending in form
  1554.      feed is interpreted as an end of page mark;  it stops the read
  1555.      operation and the form feed is not entered in the buffer. The
  1556.      portion of the record after the form feed, if any, is saved for
  1557.      the next input command.
  1558.  
  1559. File output is similarly screwy.  See the comment for the ZWrBfr function.
  1560.  
  1561. *****************************************************************************/
  1562.  
  1563. DEFAULT ZRdLin(            /* read a line */
  1564.     charptr ibuf,        /* where to put the line */
  1565.     ptrdiff_t ibuflen,    /* length of buf */
  1566.     int IfIndx,        /* index into IFiles[] */
  1567.     DEFAULT *retlen)    /* returned length of the line */
  1568. {
  1569.     unsigned int status;
  1570.     struct IFile_struct *ifile = &IFiles[IfIndx];
  1571.     char *ffptr;
  1572.     char lastchr;
  1573.  
  1574.     DBGFEN(3,"ZRdLin","");
  1575.  
  1576. /*
  1577.  * Get the next input line into ibuf,  and length into *retlen.
  1578.  */
  1579.     if (ifile->leftover_input_exists) {
  1580.         memcpy(ibuf,
  1581.                ifile->leftover_input,
  1582.                ifile->leftover_size);
  1583.         free(ifile->leftover_input);
  1584.         *retlen = ifile->leftover_size;
  1585.         ifile->leftover_input_exists = FALSE;
  1586.     } else {
  1587.         ifile->IRab.rab$l_ubf = ibuf;    /* input buffer */
  1588.         ifile->IRab.rab$w_usz = (ibuflen > 65535) ? 65535
  1589.                               : ibuflen;
  1590.  
  1591.         status = sys$get(&ifile->IRab);    /* get a record */
  1592.         if (status == RMS$_EOF) {        /* if end of file */
  1593.             DBGFEX(3,DbgFNm,"SUCCESS, hit end-of-file");
  1594.             IsEofI[IfIndx] = TRUE;
  1595.             return SUCCESS;
  1596.         }
  1597.         if (status != RMS$_NORMAL) {
  1598.             ZErMsg(status, IRab.rab$l_stv);
  1599.             DBGFEX(3,DbgFNm,"FAILURE");
  1600.             return FAILURE;
  1601.         }
  1602.         *retlen = ifile->IRab.rab$w_rsz;
  1603.     }
  1604.  
  1605. /*
  1606.  * Now do all the weird handling of special characters (see the main comment
  1607.  * for this function).
  1608.  */
  1609.     if (*retlen > 0) {            /* if not an empty line */
  1610.         if ((ffptr = memchr(ibuf, FORMFD, *retlen)) != NULL) {
  1611.             ifile->leftover_size = *retlen - (ffptr - ibuf + 1);
  1612.             if (ifile->leftover_size > 0) {
  1613.                 if ((ifile->leftover_input =
  1614.                       malloc(ifile->leftover_size))==NULL) {
  1615.                     ErrMsg(ERR_MEM);
  1616.                     DBGFEX(3,DbgFNm,"FAILURE");
  1617.                     return FAILURE;
  1618.  
  1619.                 }
  1620.                 memcpy(ifile->leftover_input,
  1621.                        ffptr+1,
  1622.                        ifile->leftover_size);
  1623.                 ifile->leftover_input_exists = TRUE;
  1624.             }
  1625.             FFPage = -1;        /* set "form feed hit" flag */
  1626.             *retlen = ffptr - ibuf;
  1627.             DBGFEX(3,DbgFNm,"SUCCESS, hit formfeed");
  1628.             return SUCCESS;
  1629.         }
  1630.         lastchr = ibuf[(*retlen)-1];
  1631.         if ((lastchr == ESCAPE) ||
  1632.             (lastchr == CRETRN) ||
  1633.             (lastchr == LINEFD) ||
  1634.             (lastchr == VRTTAB)) {
  1635.             DBGFEX(3,DbgFNm,"SUCCESS, hit ESC, CR, LF or VT");
  1636.             return SUCCESS;
  1637.         }
  1638.     }
  1639.     ibuf[*retlen] = CRETRN;        /* append carriage return */
  1640.     *retlen += 1;
  1641.     ibuf[*retlen] = LINEFD;        /* append line feed */
  1642.     *retlen += 1;
  1643.     DBGFEX(3,DbgFNm,"SUCCESS");
  1644.     return SUCCESS;
  1645. }
  1646.  
  1647.  
  1648.  
  1649.  
  1650. /*****************************************************************************
  1651.  
  1652.     ZScrOp()
  1653.  
  1654.     This function is called to perform special screen functions.
  1655.  
  1656. *****************************************************************************/
  1657.  
  1658. VVOID ZScrOp(DEFAULT OpCode)        /* do a screen operation */
  1659. {
  1660.     int index;
  1661.     static int map[] = {
  1662.         1,    /* 0 - VT52 is a VT52 */
  1663.         2,    /* 1 - VT61 is a VT61 */
  1664.         1,    /* 2 - VT100 in VT52 mode is a VT52 */
  1665.         0,    /* 3 - unused */
  1666.         3,    /* 4 - VT100 in ANSI mode is a VT100 */
  1667.         0,    /* 5 - unused */
  1668.         0,    /* 6 - VT05 is a VT05 */
  1669.         0,    /* 7 - unused */
  1670.         3,    /* 8 - VT102 is a VT100 */
  1671.         0,    /* 9 - unused */
  1672.         3,    /* 10 - VK100 is a VT100 */
  1673.         3,    /* 11 - VT200 in VT200 mode is a VT100 */
  1674.         3,    /* 12 - VT200 in VT100 mode is a VT100 */
  1675.         1,    /* 13 - VT200 in VT52 mode is a VT52 */
  1676.     };
  1677.     struct strng
  1678.         {
  1679.         charptr strt;
  1680.         DEFAULT len;
  1681.         };
  1682.     static struct strng CUP[] = {        /* cursor up one line */
  1683.         {"\232\0\0\0\0",    5},    /* VT05 - ? */
  1684.         {"\033A",        2},    /* VT52 - ESC A */
  1685.         {"",            0},    /* VT61 */
  1686.         {"\033[A",        3}    /* VT100 - ESC [ A */
  1687.     };
  1688.     static struct strng EEL[] = {        /* erase to end of line */
  1689.         {"\36",            1},    /* VT05 - RS */
  1690.         {"\033K\r",        3},    /* VT52 - ESC K CR */
  1691.         {"",            0},    /* VT61 */
  1692.         {"\033[K",        3}    /* VT100 - ESC [ K */
  1693.     };
  1694.     static struct strng ROF[] = {        /* reverse video on */
  1695.         {"",            0},    /* VT05 */
  1696.         {"",            0},    /* VT52 */
  1697.         {"",            0},    /* VT61 */
  1698.         {"\033[m",        3}    /* VT100 - ESC [ m */
  1699.     };
  1700.     static struct strng RON[] = {        /* reverse video off */
  1701.         {"",            0},    /* VT05 */
  1702.         {"",            0},    /* VT52 */
  1703.         {"",            0},    /* VT61 */
  1704.         {"\033[7m",        4}    /* VT100 - ESC [ 7 m */
  1705.     };
  1706.  
  1707.     if (CrType == UNTERM)        /* if unknown terminal type */
  1708.         return;            /* can't do screen operations */
  1709.  
  1710. /*
  1711.  * The numbering used for CrType comes from TECO-11.  Convert it to get an
  1712.  * index into the string arrays.
  1713.  */
  1714.  
  1715.     index = map[CrType];
  1716.  
  1717.     switch (OpCode) {
  1718.         case SCR_CUP:  ZDspBf(CUP[index].strt, CUP[index].len);  break;
  1719.         case SCR_EEL:  ZDspBf(EEL[index].strt, EEL[index].len);  break;
  1720.         case SCR_ROF:  ZDspBf(ROF[index].strt, ROF[index].len);  break;
  1721.         case SCR_RON:  ZDspBf(RON[index].strt, RON[index].len);  break;
  1722.     }
  1723. }
  1724.  
  1725. /*****************************************************************************
  1726.  
  1727.     ZSetTT()
  1728.  
  1729.     This function sets or clears terminal parameters.  The only terminal
  1730. parameters that TECO can set are
  1731.  
  1732.     1. whether the terminal can display 8-bit characters
  1733.     2. the number of rows
  1734.     3. the number of columns
  1735.  
  1736. *****************************************************************************/
  1737.  
  1738. DEFAULT ZSetTT(        /* tell operating system that we set the terminal */
  1739. DEFAULT TTWhat,        /* what terminal parameter to set */
  1740. DEFAULT TTVal)        /* what to set it to */
  1741. {
  1742.     unsigned int status;
  1743.     struct tt_mode_iosb_struct mode_iosb;
  1744.  
  1745.     if (!TOChan)                /* if it's not a terminal */
  1746.     return(SUCCESS);
  1747.  
  1748. /*
  1749.  * Modify the terminal characteristics.
  1750.  */
  1751.     switch (TTWhat) {
  1752.     case TT8BIT:    tt_chars.lw2.tt$v_eightbit = TTVal;  break;
  1753.     case TTWIDTH:    tt_chars.nbr_columns       = TTVal;  break;
  1754.     case TTHEIGHT:    tt_chars.lw2.tt$v_page     = TTVal;  break;
  1755.     }
  1756.  
  1757. /*
  1758.  * Set the new terminal characteristics.
  1759.  */
  1760.     status = sys$qiow(    0,            /* event flag number */
  1761.             TOChan,            /* channel */
  1762.             IO$_SETMODE,        /* I/O function */
  1763.             &mode_iosb,        /* I/O status block */
  1764.             0,            /* AST routine address */
  1765.             0,            /* AST parameter */
  1766.             &tt_chars,        /* p1 */
  1767.             0,            /* p2 */
  1768.             0,            /* p3 */
  1769.             0,            /* p4 */
  1770.             0,            /* p5 */
  1771.             0);            /* p6 */
  1772.  
  1773.     if (!$VMS_STATUS_SUCCESS(status)) {
  1774.     lib$stop(status);
  1775.     }
  1776.     if (!$VMS_STATUS_SUCCESS(mode_iosb.io_status)) {
  1777.     lib$stop(mode_iosb.io_status);
  1778.     }
  1779.  
  1780.     return SUCCESS;
  1781. }
  1782.  
  1783. /*****************************************************************************
  1784.  
  1785.     ZSWild()
  1786.  
  1787.     This function searches for the next wildcard filename.  It
  1788. is called when the user executes an "EN$" or ":EN$" command.  If the user
  1789. executes an "ENfilename$" command,  the ZPWild function is called,  not this
  1790. function.
  1791.  
  1792.     This function returns
  1793.  
  1794.         1. SUCCESS if the filename buffer has a new file name
  1795.         2. FAILURE if the search failed somehow other than FILENF
  1796.         3. FILENF if no more occurrences of the wildcard exist
  1797.  
  1798. *****************************************************************************/
  1799.  
  1800. DEFAULT ZSWild(void)        /* search for next wildcard filename */
  1801. {
  1802.     unsigned int status;
  1803.  
  1804.     DBGFEN(1,"ZSWild","");
  1805.  
  1806.     status = sys$search(&WFab);        /* search for file */
  1807.     if ((status == RMS$_FNF) ||        /* if file not found or */
  1808.         (status == RMS$_NMF)) {        /* no more files */
  1809.         DBGFEX(1,DbgFNm,"FILENF");
  1810.         return FILENF;
  1811.     }
  1812.  
  1813.     if (status != RMS$_NORMAL) {
  1814.         ZErMsg(status, WFab.fab$l_stv);
  1815.         if (!$VMS_STATUS_SUCCESS(status)) {
  1816.             DBGFEX(1,DbgFNm,"FAILURE");
  1817.             return FAILURE;
  1818.         }
  1819.     }
  1820.  
  1821.     FBfPtr = FBfBeg + WNam.nam$b_rsl;    /* resultant name length */
  1822.  
  1823. #if DEBUGGING
  1824.     sprintf(DbgSBf,"SUCCESS, FBf = \"%.*s\"",(int)(FBfPtr-FBfBeg),FBfBeg);
  1825.     DbgFEx(1,DbgFNm,DbgSBf);
  1826. #endif
  1827.     return SUCCESS;
  1828. }
  1829.  
  1830. /*****************************************************************************
  1831.  
  1832.     ZTrmnl()
  1833.  
  1834.     This function sets up the input/output of commands.  Usually, that
  1835. means the input/output channels to the terminal,  but TECOC might be run
  1836. from a command procedure (under VMS) or a script file (under __UNIX__),  and
  1837. that possibility must be handled.  In addition,  the handling of interrupts
  1838. is found here.
  1839.     In general,  this function must:
  1840.  
  1841.         1. Set TIChan so it can be used to read commands
  1842.         2. Set TOChan so it can be used for output
  1843.         3. handle interrupts
  1844.         4. initialize CrType (what kind of terminal it is)
  1845.         5. initialize EtFlag (terminal capability bits)
  1846.         6. initialize HtSize (number columns terminal has)
  1847.         7. initialize VtSize (number rows terminal has)
  1848.  
  1849. *****************************************************************************/
  1850.  
  1851. /*****************************************************************************
  1852.     On the VAX,  TECO-C can be run under two environments: interactive or
  1853. non-interactive (like batch).  In an interactive session,  it uses the
  1854. terminal for input and output.  In non-interactive mode,  it goes through RMS.
  1855. The difference is the way the I/O completes.
  1856.     In interactive mode,  each character the user types is immediately
  1857. received by TECO-C (forget type-ahead for now).  This allows TECO-C to echo
  1858. the character immediately.
  1859.     In non-interactive mode,  input comes from a file and output goes to
  1860. another file,  so RMS is used.  RMS returns a bunch of characters to TECO-C
  1861. when the user types a "terminator" character, which is defined by VMS.
  1862. In non-interactive mode, it isn't important that TECO-C echo characters
  1863. immediately.
  1864.     Because both modes must be supported, there are two separate i/o
  1865. systems in the code.  TECO-C determines if it is in interactive mode when
  1866. this function is called.  It sets TIChan to be the a channel associated with
  1867. the terminal for interactive mode,  or leaves TIChan unset (zero) for
  1868. non-interactive mode.  Other functions (ZDSpCh, ZDspBf, ZChin) test TIChan and
  1869. use either QIOs or RMS to perform I/O.
  1870.     Under VMS,  input comes from SYS$INPUT,  output goes to SYS$OUTPUT,
  1871. and control-C's come from SYS$COMMAND.  Control-Y's are not explicitly
  1872. handled by TECOC.  If SYS$COMMAND is not a terminal device,  then control-C's
  1873. are not enabled.
  1874.  
  1875. *****************************************************************************/
  1876.  
  1877. int    devclass;            /* device class */
  1878. union    ttdef devdepend;        /* device dependent attributes */
  1879. union    tt2def devdepend2;        /* device dependent attributes */
  1880. readonly $DESCRIPTOR(ter_c_desc,"SYS$COMMAND");
  1881. readonly $DESCRIPTOR(ter_i_desc,"SYS$INPUT");
  1882. readonly $DESCRIPTOR(ter_o_desc,"SYS$OUTPUT");
  1883. struct {
  1884.     short    buflen1;        /* buffer length */
  1885.     short    itmcode1;        /* item code */
  1886.     charptr    buffer1;        /* buffer address */
  1887.     short    *retlen1;        /* returned length */
  1888.     short    buflen2;        /* buffer length */
  1889.     short    itmcode2;        /* item code */
  1890.     charptr    buffer2;        /* buffer address */
  1891.     short    *retlen2;        /* returned length */
  1892.     short    buflen3;        /* buffer length */
  1893.     short    itmcode3;        /* item code */
  1894.     charptr    buffer3;        /* buffer address */
  1895.     short    *retlen3;        /* returned length */
  1896.     short    buflen4;        /* buffer length */
  1897.     short    itmcode4;        /* item code */
  1898.     charptr    buffer4;        /* buffer address */
  1899.     short    *retlen4;        /* returned length */
  1900.     int    termin;            /* item list terminator */
  1901. } itmlst = {
  1902.         4,            /* buffer length */
  1903.         DVI$_DEVCLASS,        /* device class */
  1904.         &devclass,        /* buffer address */
  1905.         0,            /* no returned length */
  1906.         4,            /* buffer length */
  1907.         DVI$_DEVDEPEND,        /* device dependent data */
  1908.         &devdepend,        /* buffer address */
  1909.         0,            /* no returned length */
  1910.         4,            /* buffer length */
  1911.         DVI$_DEVDEPEND2,    /* device dependent data */
  1912.         &devdepend2,        /* buffer address */
  1913.         0,            /* no returned length */
  1914.         0            /* item list terminator */
  1915. };
  1916. unsigned short output_sys_vfc = 1;
  1917. unsigned int rms_status;
  1918. unsigned int status;
  1919.  
  1920. VVOID    CntrlC(void);            /* make the compiler happy */
  1921.  
  1922. static VVOID enable_ctrl_c_ast(void)
  1923. {
  1924.     unsigned int status;
  1925.     struct tt_mode_iosb_struct mode_iosb;
  1926.  
  1927.     status = sys$qiow(    0,        /* event flag number */
  1928.                 TCChan,        /* channel */
  1929.                 IO$_SETMODE|
  1930.                 IO$M_CTRLCAST,    /* I/O function */
  1931.                 &mode_iosb,    /* I/O status block */
  1932.                 0,        /* AST routine address */
  1933.                 0,        /* AST parameter */
  1934.                 CntrlC,        /* control-C routine */
  1935.                 0,        /* p2 */
  1936.                 0,        /* p3 */
  1937.                 0,        /* p4 */
  1938.                 0,        /* p5 */
  1939.                 0);        /* p6 */
  1940.  
  1941.     if (!$VMS_STATUS_SUCCESS(status)) {
  1942.         lib$stop(status);
  1943.     }
  1944.     if (!$VMS_STATUS_SUCCESS(mode_iosb.io_status)) {
  1945.         lib$stop(mode_iosb.io_status);
  1946.     }
  1947. }
  1948.  
  1949. /*****************************************************************************
  1950.     This function is called whenever a control-C is typed by the user.
  1951. It is called asynchronously.
  1952. *****************************************************************************/
  1953. static VVOID CntrlC(void)            /* control-C AST routine */
  1954. {
  1955.     unsigned int status;
  1956.  
  1957.     if (EtFlag & ET_TRAP_CTRL_C) {        /* if user wants it */
  1958.         EtFlag &= ~ET_TRAP_CTRL_C;    /* turn off bit */
  1959.     } else {
  1960.         if (EtFlag & ET_MUNG_MODE) {    /* if in MUNG mode */
  1961.             TAbort(EXIT_SUCCESS);
  1962.         }
  1963.         GotCtC = TRUE;            /* set "stop soon" flag */
  1964.     }
  1965.  
  1966.     status = sys$cancel((long)TOChan);    /* cancel current output */
  1967.     if (!$VMS_STATUS_SUCCESS(status)) {
  1968.         lib$stop(status);
  1969.     }
  1970.     enable_ctrl_c_ast();            /* re-enable the AST */
  1971. }
  1972.  
  1973. static VVOID open_terminal_input(void)
  1974. {
  1975.         struct getxxx_iosb_struct getdvi_iosb;
  1976.  
  1977.     status = sys$getdviw(    1,        /* event flag number */
  1978.                 0,        /* channel */
  1979.                 &ter_i_desc,    /* device name */
  1980.                 &itmlst,    /* item list */
  1981.                 &getdvi_iosb,    /* i/o status block */
  1982.                 0,        /* AST routine address */
  1983.                 0,        /* AST parameter */
  1984.                 0);        /* reserved by DEC */
  1985.     if (!$VMS_STATUS_SUCCESS(status)) {
  1986.         devclass = DC$_MISC;
  1987.     } else {
  1988.         if ((!$VMS_STATUS_SUCCESS(getdvi_iosb.io_status)) &&
  1989.             (getdvi_iosb.io_status != SS$_CONCEALED)) {
  1990.             lib$stop(getdvi_iosb.io_status);
  1991.         }
  1992.     }
  1993.  
  1994.     EtFlag = ET_READ_LOWER;
  1995. #if VIDEO
  1996.     EtFlag |= ET_WAT_SCOPE;
  1997. #endif
  1998.     if (devclass == DC$_TERM) {            /* if it's a terminal */
  1999.         if (!devdepend.tt$v_lower) {        /* if has no lowercase */
  2000.             EtFlag &= ~ET_READ_LOWER;   /* don't read lowercase */
  2001.         }
  2002.         status = sys$assign(    &ter_i_desc,    /* device name */
  2003.                     &TIChan,    /* channel */
  2004.                     0,        /* access mode */
  2005.                     0);        /* mailbox name */
  2006.         if (!$VMS_STATUS_SUCCESS(status)) {
  2007.             lib$stop(status);
  2008.         }
  2009.         return;
  2010.     }
  2011.  
  2012.     TIBERc = TIBBeg = ZAlloc((SIZE_T)SOBSIZE);
  2013.     TIBEnd = (TIBBeg + SOBSIZE) - 1;
  2014.     TIBPtr = TIBERc;            /* causes the initial read */
  2015.  
  2016.     TIFab = cc$rms_fab;            /* initialize FAB defaults */
  2017.     TIFab.fab$b_fac = FAB$M_GET;        /* file access = read only */
  2018.     TIFab.fab$l_fna = ter_i_desc.dsc$a_pointer;
  2019.     TIFab.fab$b_fns = ter_i_desc.dsc$w_length;
  2020.     TIFab.fab$l_fop = FAB$M_INP |        /* this is SYS$INPUT and */
  2021.               FAB$M_SQO;        /* sequential access only */
  2022.  
  2023.     rms_status = sys$open(&TIFab);        /* open terminal input */
  2024.     if (rms_status != RMS$_NORMAL) {
  2025.         lib$stop(rms_status, TIFab.fab$l_stv);
  2026.     }
  2027.     TIRab = cc$rms_rab;            /* initialize RAB defaults */
  2028.     TIRab.rab$l_fab = &TIFab;        /* address of associated FAB */
  2029.     TIRab.rab$b_rac = RAB$C_SEQ;        /* rec. access = sequential */
  2030.     TIRab.rab$l_rop = RAB$M_LOC |        /* use locate mode and */
  2031.               RAB$M_RAH;        /* read ahead */
  2032.     TIRab.rab$l_ubf = TIBBeg;        /* input buffer */
  2033.     TIRab.rab$w_usz = SOBSIZE;        /* input buffer size */
  2034.  
  2035.     rms_status = sys$connect(&TIRab);    /* connect terminal input */
  2036.     if (rms_status != RMS$_NORMAL) {
  2037.         lib$stop(rms_status, TIRab.rab$l_stv);
  2038.     }
  2039. }
  2040.  
  2041. static VVOID open_terminal_output(void)
  2042. {
  2043.     struct getxxx_iosb_struct getdvi_iosb;
  2044.     struct tt_mode_iosb_struct mode_iosb;
  2045.  
  2046.     status = sys$getdviw(    1,        /* event flag number */
  2047.                 0,        /* channel */
  2048.                 &ter_o_desc,    /* device name */
  2049.                 &itmlst,    /* item list */
  2050.                 &getdvi_iosb,    /* i/o status block */
  2051.                 0,        /* AST routine address */
  2052.                 0,        /* AST parameter */
  2053.                 0);        /* reserved by DEC */
  2054.     if (!$VMS_STATUS_SUCCESS(status)) {
  2055.     devclass = DC$_MISC;
  2056.     } else if ((!$VMS_STATUS_SUCCESS(getdvi_iosb.io_status)) &&
  2057.            (getdvi_iosb.io_status != SS$_CONCEALED)) {
  2058.     lib$stop(getdvi_iosb.io_status);
  2059.     }
  2060.     if (devclass == DC$_TERM) {            /* if it's a terminal */
  2061.     if (!devdepend.tt$v_lower)        /* if won't show lowercase */
  2062.         EuFlag = EU_LOWER;            /* set lowercase */
  2063.     if (devdepend.tt$v_scope)        /* if scope */
  2064.         EtFlag |= ET_SCOPE;            /* set scope bit */
  2065.     if (devdepend.tt$v_eightbit)        /* can show 8-bit */
  2066.         EtFlag |= ET_EIGHTBIT;
  2067.     if (devdepend2.tt2$v_deccrt2) {        /* VT200 compatible? */
  2068.         CrType = VT200;
  2069.         EtFlag |= ET_VT200;            /* VT200 mode */
  2070.         EtFlag |= ET_ACCENT_GRAVE;        /* VT200 mode */
  2071.     } else if (devdepend2.tt2$v_deccrt)    /* VT100 compatible? */
  2072.         CrType = VT100;
  2073.     else if (devdepend2.tt2$v_ansicrt)    /* ANSI compatible? */
  2074.         CrType = VK100;
  2075.     else                    /* default is VT52 */
  2076.         CrType = VT52;
  2077.  
  2078.     status = sys$assign(    &ter_o_desc,    /* device name */
  2079.                 &TOChan,    /* channel */
  2080.                 0,        /* access mode */
  2081.                 0);        /* mailbox name */
  2082.     if (!$VMS_STATUS_SUCCESS(status)) {
  2083.         lib$stop(status);
  2084.     }
  2085.  
  2086. /*
  2087.  * Get the current terminal characteristics so that later setmodes work.
  2088.  */
  2089.     status = sys$qiow(    0,        /* event flag number */
  2090.                 TOChan,        /* channel */
  2091.                 IO$_SENSEMODE,    /* I/O function */
  2092.                 &mode_iosb,    /* I/O status block */
  2093.                 0,        /* AST routine address */
  2094.                 0,        /* AST parameter */
  2095.                 &tt_chars,    /* p1 */
  2096.                 0,        /* p2 */
  2097.                 0,        /* p3 */
  2098.                 0,        /* p4 */
  2099.                 0,        /* p5 */
  2100.                 0);        /* p6 */
  2101.     if (!$VMS_STATUS_SUCCESS(status)) {
  2102.         lib$stop(status);
  2103.     }
  2104.     if (!$VMS_STATUS_SUCCESS(mode_iosb.io_status)) {
  2105.         lib$stop(mode_iosb.io_status);
  2106.     }
  2107. #if VIDEO
  2108.     HtSize = tt_chars.nbr_columns;        /* horizontal size */
  2109.     VtSize = tt_chars.lw2.tt$v_page;    /* vertical size */
  2110. #endif
  2111.     return;
  2112.     } else {                    /* else not a terminal */
  2113.     TOBEnd = &TOBBeg[SOBSIZE]-1;
  2114.     TOBPtr = &TOBBeg[0];
  2115.  
  2116.     TOFab = cc$rms_fab;            /* initialize FAB defaults */
  2117.     TOFab.fab$b_fac = FAB$M_PUT;        /* file access = write only */
  2118.     TOFab.fab$l_fna = ter_o_desc.dsc$a_pointer;
  2119.     TOFab.fab$b_fns = ter_o_desc.dsc$w_length;
  2120.     TOFab.fab$b_fsz = 2;            /* fixed size cntrl area=2 */
  2121.     TOFab.fab$b_org = FAB$C_SEQ;        /* organization=sequential */
  2122.     TOFab.fab$b_rat = FAB$M_PRN;        /* print file format */
  2123.     TOFab.fab$b_rfm = FAB$C_VFC;        /* variable w/fixed control */
  2124.  
  2125.     rms_status = sys$create(&TOFab);    /* open terminal output */
  2126.     if (rms_status != RMS$_NORMAL) {
  2127.         lib$stop(rms_status, TOFab.fab$l_stv);
  2128.     }
  2129.  
  2130.     TORab = cc$rms_rab;            /* initialize RAB defaults */
  2131.     TORab.rab$l_fab = &TOFab;        /* addr of associated FAB */
  2132.     TORab.rab$l_rhb = &output_sys_vfc;    /* print control buffer */
  2133.     TORab.rab$l_rop = RAB$M_WBH;        /* write behind */
  2134.     TORab.rab$l_rbf = &TOBBeg[0];        /* output buffer */
  2135.  
  2136.     rms_status = sys$connect(&TORab); /* connect terminal output */
  2137.     if (rms_status != RMS$_NORMAL) {
  2138.         lib$stop(rms_status, TORab.rab$l_stv);
  2139.     }
  2140.     }
  2141. }
  2142.  
  2143. static VVOID open_terminal_command(void)
  2144. {
  2145.         struct getxxx_iosb_struct getdvi_iosb;
  2146.  
  2147.     status = sys$getdviw(    1,        /* event flag number */
  2148.                 0,        /* channel */
  2149.                 &ter_c_desc,    /* device name */
  2150.                 &itmlst,    /* item list */
  2151.                 &getdvi_iosb,    /* i/o status block */
  2152.                 0,        /* AST routine address */
  2153.                 0,        /* AST parameter */
  2154.                 0);        /* reserved by DEC */
  2155.     if (!$VMS_STATUS_SUCCESS(status)) {
  2156.         devclass = DC$_MISC;
  2157.     } else {
  2158.         if ((!$VMS_STATUS_SUCCESS(getdvi_iosb.io_status)) &&
  2159.             (getdvi_iosb.io_status != SS$_CONCEALED)) {
  2160.             lib$stop(getdvi_iosb.io_status);
  2161.         }
  2162.     }
  2163.     if (devclass == DC$_TERM) {            /* if terminal */
  2164.         status = sys$assign(    &ter_c_desc,    /* device name */
  2165.                     &TCChan,    /* channel */
  2166.                     0,        /* access mode */
  2167.                     0);        /* mailbox name */
  2168.         if (!$VMS_STATUS_SUCCESS(status)) {
  2169.             lib$stop(status);
  2170.         }
  2171.         signal(SIGINT,SIG_IGN);        /* ignore SIGINT */
  2172.         enable_ctrl_c_ast();        /* enable control-C */
  2173.     }
  2174. }
  2175.  
  2176. VVOID ZTrmnl(void)        /* set up I/O to the terminal */
  2177. {
  2178.     open_terminal_input();        /* open SYS$INPUT */
  2179.     open_terminal_output();        /* open SYS$OUTPUT */
  2180.     open_terminal_command();    /* open SYS$COMMAND */
  2181. }
  2182.  
  2183. /*****************************************************************************
  2184.  
  2185.     ZVrbos()
  2186.  
  2187.     This function displays the verbose form of error messages.
  2188.  
  2189. *****************************************************************************/
  2190.  
  2191. VVOID ZVrbos(WORD ErrNum, char *ErMnem)
  2192. {
  2193.     static char HlpStr[12] = " Errors xxx";
  2194.  
  2195.     MEMMOVE(&HlpStr[8], ErMnem, (SIZE_T)3);
  2196.     ZHelp(HlpStr, &HlpStr[10], FALSE, FALSE);
  2197. }
  2198.  
  2199. /*****************************************************************************
  2200.  
  2201.     ZWrBfr()
  2202.  
  2203.     This function writes a buffer to a file,  one line at a time.  It is
  2204. passed an output file index and pointers to the beginning and end of the
  2205. buffer to be output.
  2206.  
  2207.     On output, TECO scans the text buffer for carriage return,  line
  2208. feed, vertical tab and form feed characters.  Each such character delimits
  2209. the end of an output record.  If the line ends with exactly CR/LF, the CR/LF
  2210. are not output with the record,  otherwise the record is output in its
  2211. entirety.  If a record ends with a CR/LF preceded by an ESCAPE,  then the
  2212. ESCAPE and the CR/LF are output with the record.
  2213.  
  2214. *****************************************************************************/
  2215.  
  2216. DEFAULT ZWrBfr(
  2217.     DEFAULT OfIndx,        /* index into OFiles array */
  2218.         charptr BfrBeg,        /* address of output buffer beginning */
  2219.     charptr BfrEnd)        /* address of output buffer end */
  2220. {
  2221.     charptr    BfrPtr = BfrBeg;    /* output buffer pointer */
  2222.     ptrdiff_t line_len;        /* length of current output line */
  2223.  
  2224. #if DEBUGGING
  2225.     static char *DbgFNm = "ZWrBfr";
  2226.     sprintf(DbgSBf,"OfIndx = %d, BfrBeg = %ld, BfrEnd = %ld",
  2227.         OfIndx, Zcp2ul(BfrBeg), Zcp2ul(BfrEnd));
  2228.     DbgFEn(2,DbgFNm,DbgSBf);
  2229. #endif
  2230.     do {                /* do for each line */
  2231.  
  2232. /*
  2233.  * Set BfrBeg to the beginning of the line to be output. Find the end of the
  2234.  * line,  set BfrPtr to the character after it.
  2235.  */
  2236.         BfrBeg = BfrPtr;
  2237.         while (BfrPtr <= BfrEnd) {
  2238.             if (*BfrPtr == CRETRN) {
  2239.             BfrPtr++;
  2240.             if ((BfrPtr <= BfrEnd) && (*BfrPtr == LINEFD)) {
  2241.                 line_len = BfrPtr - BfrBeg - 1;
  2242.                 BfrPtr ++;
  2243.                 break;
  2244.             } else {
  2245.                 BfrPtr--;
  2246.             }
  2247.             } else if (*BfrPtr == ESCAPE) {
  2248.             if ((BfrPtr+2 <= BfrEnd) && (*(BfrPtr+1) == CRETRN) &&
  2249.                             (*(BfrPtr+2) == LINEFD)) {
  2250.                 BfrPtr += 3;
  2251.                 line_len = BfrPtr - BfrBeg;
  2252.                 break;
  2253.             }
  2254.             } else if (IsEOL(*BfrPtr)) {    /* LF, VT or FF? */
  2255.                 BfrPtr++;
  2256.                 line_len = BfrPtr - BfrBeg;
  2257.                 break;
  2258.             }
  2259.             ++BfrPtr;
  2260.         }
  2261.  
  2262.         OFiles[OfIndx].ORab.rab$l_rbf = BfrBeg;        /* buffer */
  2263.         OFiles[OfIndx].ORab.rab$w_rsz = line_len;    /* size */
  2264.  
  2265. #if DEBUGGING
  2266.         sprintf(DbgSBf,"calling sys$put, line_len = %d", line_len);
  2267.         DbgFMs(2,DbgFNm,DbgSBf);
  2268. #endif
  2269.         status = sys$put(&OFiles[OfIndx].ORab);    /* output the record */
  2270.         if (status != RMS$_NORMAL) {        /* if it didn't work */
  2271.             ZErMsg(status, OFiles[OfIndx].ORab.rab$l_stv);
  2272.             ErrMsg(ERR_UWL);
  2273.             DBGFEX(2,DbgFNm,"FAILURE");
  2274.             return FAILURE;
  2275.         }
  2276.     } while (BfrPtr <= BfrEnd);
  2277.  
  2278.     DBGFEX(2,DbgFNm,"SUCCESS");
  2279.     return SUCCESS;
  2280. }
  2281.